about:benjie

Random learnings and other thoughts from an unashamed geek

CoffeeScript: JavaScript, but Clearer

| Comments

I really like CoffeeScript. I really like JavaScript. I’m trying to get into the habit of writing more CoffeeScript since, I think, it allows me to express myself clearer and more concisely, leading to shorter code and (hopefully) less mistakes/bugs. It also makes jumping back into code a month later a much simpler affair since reading the code is so much easier.

The following JavaScript creates a new closure inside each iteration of a loop to store the value of the loop variable i into the closure’s local variable j so that we don’t just console.log(10) 10 times. Though this example is trivial it represents a common method for solving closure related issues in asynchronous code.

JavaScript closure required for correct output
1
2
3
4
5
6
7
8
for (var i = 0; i < 10; i++) {
  (function(){
    var j = i;
    delay(0, function(){
      console.log(j);
    });
  })();
}

The following CoffeeScript does exactly the same thing, you can see the translation line by line from the JavaScript. However once you’ve learnt the syntax you can much more clearly see what is going on with the CoffeeScript than in the verbose and parenthesis-heavy JavaScript above.

.coffee.jsCoffeeScript to do the same thing
1
2
3
4
5
for i in [0..10]
  do ->
    j = i
    delay 0, ->
      console.log j

As a bonus,

ASA Regulating ‘Unlimited’ Broadband Claims

| Comments

Strict guidelines will also be placed on internet providers which offer so-called unlimited packages, where users can download to their heart’s content. If a user incurs an “additional charge or suspension of service as a consequence of exceeding a usage threshold,” the ISP cannot use the term “unlimited”.

Finally! I hate it when providers are allowed to say ‘Unlimited’ and then place a limit on it (generally via a Fair Usage Policy). What a load of rubbish! I’m a heavy bandwidth user so it makes it very hard for me to find out what the limit is and then choose the relevant provider. Fortunately Virgin’s XXL broadband truly is unlimited - at least for now!

Octopress/Disqus Issue Resolved

| Comments

I was having an issue with Disqus - my comments were showing on post pages, but the comment count was not. Turns out that this is a simple to fix error relating to JavaScript scope.

Scope issue

The developer of Octopress has kindly protected our window object from being polluted with various unnecessary variables by wrapping the whole disqus include in an anonymous function.

However, the Disqus script actually injects another <script> element into the <head> (or <body>) of the page. This injected script, like all other scripts on the page, inherits the global (window) scope, and not the scope of this anonymous function. Thus it will not have access to the disqus variables such as disqus_shortname defined within the anonymous function. Without these variables, disqus loads such domains as undefined.disqus.com which is not very helpful!

Solution

The fix is simple - open up source/_includes/disqus.html and move the beginning of the anonymous function ((function () {) so that it does not contain the var disqus_* variable definitions. We also need to insert a couple of semi-colons that have been accidentally omitted. Here’s the resulting file:

Modified disqus include to fix disqus comment count. (source/_includes/disqus.html) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{% comment %} Load script if disquss comments are enabled and `page.comments` is either empty (index) or set to true {% endcomment %}
{% if site.disqus_short_name and page.comments != false %}
<script type="text/javascript">
      var disqus_shortname = '{{ site.disqus_short_name }}';
      {% if page.comments == true %}
        {% comment %} `page.comments` can be only be set to true on pages/posts, so we embed the comments here. {% endcomment %}
        // var disqus_developer = 1;
        var disqus_identifier = '{{ site.url }}{{ page.url }}';
        var disqus_url = '{{ site.url }}{{ page.url }}';
        var disqus_script = 'embed.js';
      {% else %}
        {% comment %} As `page.comments` is empty, we must be on the index page. {% endcomment %}
        var disqus_script = 'count.js';
      {% endif %}

    (function () {
      var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
      dsq.src = 'http://' + disqus_shortname + '.disqus.com/' + disqus_script;
      (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
    }());
</script>
{% endif %}

One more thing

If you want your links to be absolute, then you should set root to be your root URL in _config.yml - e.g. root: http://www.benjiegillam.com/ rather than root: /. This may or may not be required for Disqus to function properly.

EDIT: @Octopress has confirmed that root must not contain the scheme and host.

Bonus

Now that I’ve implemented the above, my comments and comment counts successfully display on my benjiegillam.dev site (hosted by Pow)!

Using Sed to Replace Newlines

| Comments

Annoyingly, Mac OS X’s sed is not 100% compatible with GNU sed, and so this solution from StackOverflow did not immediately solve my issue:

Or use this solution with sed:
sed ':a;N;$!ba;s/\n/ /g'
This will read the whole file in a loop, then replaces the newline(s) with a space.

Update: explanation.

  1. create a register via :a
  2. append the current and next line to the register via N
  3. if we are before the last line, branch to the created register $!ba ($! means not to do it on the last line (as there should be one final newline)).
  4. finally the substitution replaces every newline with a space on the pattern space (which is the contents of the a register = the whole file.

The solution I found was to split the command up into explicit separate commands:

Replacing newlines with spaces using sed on Mac OS X
1
sed -e ':a' -e 'N' -e '$!ba' -e 's/\n/ /g'

Octopress UTF-8 Issues

| Comments

After running exitwp to import my blog, I ran rake generate to build it, and got the following issue:

$ rake generate
(in /Users/benjiegillam/Documents/Blog/octopress)
## Generating Site with Jekyll
Configuration from /Users/benjiegillam/Documents/Blog/octopress/_config.yml
unchanged sass/screen.scss
Building site: source -> public
/Users/benjiegillam/Documents/Blog/octopress/plugins/raw.rb:11:in `gsub': invalid byte sequence in UTF-8 (ArgumentError)
    from /Users/benjiegillam/Documents/Blog/octopress/plugins/raw.rb:11:in `unwrap'
    [...]

However, converting the file was perfectly valid UTF-8 as confirmed by an iconv -c conversion followed by a diff -u.

After a quick bit of hacking in the octopress/plugins/raw.rb file to spit out the content that was being converted, I found the file at fault. After some iteration I got to the root of the issue - Octopress’ default markdown parser, rdiscount, REALLY doesn’t like UTF-8 characters in URLs. I’ve built a test here:

From Wordpress to Octopress

| Comments

I had a few issues going from Wordpress to Octopress (which I did using exitwp) - I’ve outlined some of my solutions below.

Crossed out code blocks

The markdown produced by pandoc (an exitwp dependency) uses ~~~~ in places to denote a code block. However, rdiscount (Octopress’ markdown parser) recognises this instead as strike-through. A simple bash command fixes this (though it does lose some of the formatting details).

Fix tildes generated by pandoc (exitwptildes.sh) download
1
2
3
4
5
for I in *; do sed -i '' -e 's/^~~~~ {\(.*\)}$/\
<!-- \1 -->\
```/g' $I; done
for I in *; do sed -i '' -e 's/^~~~~$/\
```/g' $I; done

Line breaks in links

For some reason exitwp added some linebreaks into the markup for the links. And for some other reason, octopress’ style sheet (screen.css) tells <a> tags that their white-space should be pre-wrap, these two issues combine to give you broken links.

This next command should fix these newline issues.

NodeJS: Express/Socket.io/RedisStore Headache

| Comments

If you’re trying to access a session from a socket.io socket, I recommend following these instructions which work great for MemoryStore. However for RedisStore you need to do a little more work because the object returned is just a JSON object - not a Session object as it should be. I’ve hacked around it by adding the following (CoffeeScript) to convert it to a Session object if required:

.coffee.jsMake sure ‘session’ is a Session object
1
2
3
4
5
if session and not session.prototype?.reload
    req =
        sessionStore: sessionStore
        sessionID: data.sessionID
    session = new express.session.Session req, session

immediately inside the sessionStore.get callback.

Node.JS: Clean Restart and Faster Development With Nodemon

| Comments

If you’re using nodemon to automatically restart your node/coffee server process when the source code changes (and if you’re not, why not?), you may find (as I did) that it can kill the script quite abruptly. If you want to do something when the code shuts down (close connections, flush to database/disk/redis/memcached, etc) then you can do so by intercepting the SIGUSR2 signal that nodemon uses to kill your script, and then setting up these actions. Once these actions are complete, you can exit but nodemon will see that as a crash and stop restarting. So you then have to kill your app again with SIGUSR2. Here’s the solution I use in CoffeeScript (click Toggle for JavaScript):

.coffee.jsCleanly restart on nodemon SIGUSR2 (.coffee)
1
2
3
4
5
6
7
8
9
10
11
12
# Alias for setTimeout that reorders parameters to look neater in CoffeeScript
delay = (ms, cb) -> setTimeout cb, ms
# Handle SIGUSR2, but only once
process.once 'SIGUSR2', ->
  console.log 'Doing shutdown tasks...'
  delay 5000, ->
    console.log 'All done, exiting'
    # Kill ourself with the SIGUSR2 signal again
    process.kill process.pid, 'SIGUSR2'
# This next line just to prevent the app exiting in case you want to use this as a demo
delay 99999999, ->
  console.log 'App exiting naturally'

By the way, to install nodemon globally: sudo npm install -g nodemon

Manually Migrating FileVault

| Comments

DISCLAIMER: As always, you follow this at your own risk - keep good backups, I take no responsibility for you doing anything whatsoever - you’re a big boy/girl now, take responsibility for your own actions!

So you can’t use MigrationAssistant because you already have an account (Alice) on the new machine (New) and don’t have the disk space on the old one (Old) to turn FV off? Fear not! Let’s assume the username you want to move is steve:

  1. As Alice, create (admin) account on New with same username, steve, and same password, and enable FileVault.
  2. Replace /Users/steve/steve.sparsebundle on New with /Users/.steve/steve.sparsebundle from Old. (you could use scp, rsync, an external hard drive, or any other method to transfer these files) (I did this with steve logged in, but you can do it logged out though the path may be different)
  3. As Alice, fix the permissions on New: chown -R steve /Users/steve
  4. Log in as steve on New (unlocks the sparsebundle and mounts it at /Users/steve)
  5. Fix permissions again: either as Alice or steve, sudo chown -R steve /Users/steve
  6. Log out an in again Voila!

If this helps you, please drop me a comment :)