Are You Still There?

A scenario: you want to update some content on your page periodically, but you don’t want to waste requests, resources, cycles, etc. on running your script while the user is obviously not interacting with the page. What do you do?

Here’s a jQuery extension I call “Still Alive” which handles this for you. It will run your functions periodically while the user is interacting with the page, but then it will go to sleep and stop executing them if the user goes away, and resume when the user comes back.

Implementation

/*!
* Still Alive v1.2
* http://github.com/sidewaysmilk/still-alive
*
* Copyright 2011, Justin Force
* Licensed under the BSD 3-Clause License
*/


/*jslint browser: true, indent: 2 */
/*global jQuery */

(function ($) {

  'use strict';

  // default values for optional arguments
  var DEFAULT_WAKEEVENTS = 'mousemove mousedown mouseup keydown keyup',
    DEFAULT_INTERVAL     = 60000,
    DEFAULT_IMMEDIATELY  = true;

  // sugar. Just get the current time in milliseconds
  function getTime() {
    return (new Date()).getTime();
  }

  $.stillAlive = function (callback, interval, immediately, wakeEvents) {

    var ptr,                // pointer to the interval so it can be cleared from outside
      args,                 // object containing optional arguments
      awake = true,         // awake status. Are we awake?
      lastSeen = getTime(); // the last time the user was seen (a wake event triggered)

    // For named arguments, copy the arguments object and assign its supported
    // properties.
    if (typeof interval === 'object') {
      args = interval;
      interval = args.interval;
      immediately = args.immediately;
      wakeEvents = args.wakeEvents;
    }

    // set default values for optional arguments
    if (interval === undefined) {
      interval = DEFAULT_INTERVAL;
    }
    if (immediately === undefined) {
      immediately = DEFAULT_IMMEDIATELY;
    }
    if (wakeEvents === undefined) {
      wakeEvents = DEFAULT_WAKEEVENTS;
    }

    // true if it's been (1.5 x interval) milliseconds
    function timeToSleep() {
      return (getTime() - lastSeen > (interval + (interval / 2)));
    }

    // set status to awake and update the lastSeen time, then execute the
    // callback.
    function wake() {
      if (!awake) {
        callback();
      }
      awake = true;
      lastSeen = getTime();
    }

    // set status to !awake (asleep)
    function sleep() {
      awake = false;
    }

    $(window).bind(wakeEvents, wake);

    // if enough time has passed without a wake event, sleep. If we happen to
    // be awake, execute the callback.
    ptr = setInterval(function () {
      if (timeToSleep()) {
        sleep();
      }
      if (awake) {
        callback();
      }
    }, interval);

    // if we're supposed to run immediately, execute the callback once
    if (immediately) {
      callback();
    }

    return ptr;
  };

}(jQuery));

Examples

Say I have a function called update defined elsewhere. I want update to be called every 60 seconds unless the user doesn’t seem to be around. I’d just

$.stillAlive(update);

How about every 15 seconds?

$.stillAlive(update, 15);

Let’s toggle a class of some elements every 90 seconds, but only if the user has clicked or typed something, and don’t run it immediately after being set.

$.stillAlive(function() {
  $('.togglies').toggleClass('toggly');
}, 90, false, 'click keyup');

The previous code could also be more explicitly called thusly:

$.stillAlive(function() {
  $('.togglies').toggleClass('toggly');
}, {
  interval: 90,
  immediately: false,
  wakeEvents: 'click keyup'
});

And for good measure, here’s a call using object literal notation, but only adjusting the interval:

$.stillAlive(update, { interval: 5 });

Note that the stillAlive method returns the intervalID, so you can cancel your stillAlive thusly:

var sa = $.stillAlive(update);
clearInterval(sa);

GitHub

The project, like most of my work, lives at GitHub. For complete documentation, forking, and keeping up with the latest version, check out Still Alive on GitHub.

Posted in javascript | Tagged , , , , , , , , , | Leave a comment

Add Stable Merge Sort to Array and jQuery Prototypes

Some browsers’ JavaScript implementations don’t implement a stable sort, but stable sorting can be so handy if you want to, say, sort a table by multiple columns. So here’s a quick and easy way to add an efficient, stable merge sort to the Array prototype. Note that this even lets you define your own comparison function, just like JavaScript’s own Array.sort function!

Bonus!

We’ll also add this sorting function to jQuery, which already applies Array.sort for $.sort and $(selection).sort.

Implementation

/*!
 * Merge Sort in JavaScript v1.0
 * http://github.com/sidewaysmilk/merge-sort
 *
 * Copyright (c) 2011, Justin Force
 * Licensed under the BSD 3-Clause License
 */


/*jslint browser: true, indent: 2 */
/*global jQuery */

(function () {

  'use strict';

  // Add stable merge sort method to Array prototype
  if (!Array.mergeSort) {
    Array.prototype.mergeSort = function (compare) {

      var length = this.length,
        middle = Math.floor(length / 2);

      // define default comparison function if none is defined
      if (!compare) {
        compare = function (left, right) {
          if (left  <  right) {
            return -1;
          } else if (left === right) {
            return 0;
          } else {
            return 1;
          }
        };
      }

      if (length < 2) {
        return this;
      }

      function merge(left, right, compare) {

        var result = [];

        while (left.length > 0 || right.length > 0) {
          if (left.length > 0 && right.length > 0) {
            if (compare(left[0], right[0]) <= 0) {
              result.push(left[0]);
              left = left.slice(1);
            } else {
              result.push(right[0]);
              right = right.slice(1);
            }
          } else if (left.length > 0) {
            result.push(left[0]);
            left = left.slice(1);
          } else if (right.length > 0) {
            result.push(right[0]);
            right = right.slice(1);
          }
        }
        return result;
      }

      return merge(
        this.slice(0, middle).mergeSort(compare),
        this.slice(middle, length).mergeSort(compare),
        compare
      );
    };
  }

  // Add merge sort to jQuery if it's present
  if (window.jQuery !== undefined) {
    jQuery.fn.mergeSort = function (compare) {
      return jQuery(Array.prototype.mergeSort.call(this, compare));
    };
    jQuery.mergeSort = function (array, compare) {
      return Array.prototype.mergeSort.call(array, compare);
    };
  }

}());

Examples

Arrays

I have some arrays of numbers, strings, and miscellany that need sorting.

var numbers = [4, 2, 2, 43, 98, 29, 0, 4.3, 9.23],
  strings = ['Porcupine', 'dolphin', 'Squirrel', 'penguin', 'Lion'],
  miscellany = ['23', 89, 'stapler', 4];

To sort my numbers, I would just

numbers.mergeSort();
// [0, 2, 2, 4, 4.3, 9.23, 29, 43, 98]

To sort my strings, I can also just

strings.mergeSort();
// ["Lion", "Porcupine", "Squirrel", "dolphin", "penguin"]

But with the default comparison, they don’t come out alphabetical. The capitalized words come first. For a case insensitive sort, I need to define a compare function.

strings.mergeSort(function (left, right) {
  left = left.toLowerCase();
  right = right.toLowerCase();

  if (left < right) {
    return -1;
  } else if (left === right) {
    return 0;
  } else {
    return 1;
  }
});
// ["dolphin", "Lion", "penguin", "Porcupine", "Squirrel"]

That’s more like it. How about that last list of miscellany? I want my numbers first, then my words, but I want strings containing numbers treated as numbers. Pretty specific, but I can describe it with a function.

miscellany.mergeSort(function (left, right) {

  if (isNaN(left) === false) {
    left = parseFloat(left);
  }

  if (isNaN(right) === false) {
    right = parseFloat(right);
  }

  if (typeof left !== typeof right) {
    if (typeof left === 'number') {
      return -1;
    } else {
      return 1;
    }
  } else {
    if (left < right) {
      return -1;
    } else if (left === right) {
      return 0;
    } else {
      return 1;
    }
  }
});
// [4, "23", 89, "stapler"]

jQuery

Used with jQuery, you’ll probably always want to supply a compare function, so I’ll only discuss those cases. Here’s a non-trivial example. I have a table:

<table id=demo>
  <thead>
    <tr>
      <th>First Name
      <th>Last Name
      <th>Occupation
  <tbody>
    <tr>
      <td>Bob
      <td>Durp
      <td>Programmer
    <tr>
      <td>Alice
      <td>Morp
      <td>Programmer
    <tr>
      <td>Luis
      <td>Durp
      <td>Analyst
</table>

Which looks something like

First Name Last Name Occupation
Bob Durp Programmer
Alice Morp Programmer
Luis Durp Analyst

I can sort by any column. To sort by Last Name (the 2nd column):

$('#demo tbody').html($('#demo tbody tr').mergeSort(function (left, right) {

  left = $(left).find('td:nth-child(2)').text().toLowerCase();
  right = $(right).find('td:nth-child(2)').text().toLowerCase();

  if (left < right) {
    return -1;
  } else if (left === right) {
    return 0;
  } else {
    return 1;
  }
}));

And the table will be updated to look like this:

First Name Last Name Occupation
Bob Durp Programmer
Luis Durp Analyst
Alice Morp Programmer

You can see how with a little imagination and the application of a click handler, this could be extrapolated to allow real-time resorting of a table. And since it’s a stable sort, you can sort by multiple columns sequentially.

Other

You can apply this merge sort to any other compatible type in the same way (see list in the Syntax section above for compatibility).

$.mergeSort(aListOfSomeKind, compareMyListItems);

The $.mergeSort() syntax is just sugar for Array.prototype.mergeSort.call(), so the above is equivalent to

Array.prototype.mergeSort.call(aListOfSomeKind, compareMyListItems);

But just use the simpler $.mergeSort() syntax. :)

GitHub

The project, like most of my work, lives at GitHub. For complete documentation, forking, and keeping up with the latest version, check out merge-sort.js on GitHub.

Posted in javascript | Tagged , , , , , , , , , , | Leave a comment

Request Tracker Watchdog

I recently upgraded from Request Tracker 3.8.0 to 4.0.2 and started running it with FastCGI. Works great except for the odd Bad Gateway message from nginx (still haven’t figured that one out). While v4 makes a lot of improvements over v3.8, I have noticed that RT now gradually consumes more and more memory until you run out. I wrote a watchdog in Ruby to monitor RT’s memory usage and restart it. Here is my watchdog script and the Upstart script I use to start and stop it.

/opt/rt4/bin/rt-watchdog

Check RT’s memory usage every 2 seconds. If its usage surpasses 128MB, restart it. If this script gets a TERM signal, shut down RT before exiting.

#!/usr/bin/env ruby

require 'timeout'

# RT binary name without path
BIN = 'rt-server.fcgi'

# command to get PID of RT
PID = "ps -e | grep #{BIN} | grep -v grep | awk '{print $1}'"

# command to start RT
START = "spawn-fcgi -u www-data -g www-data -a 127.0.0.1 -p 9000 /opt/rt4/sbin/#{BIN}"

# command to stop RT
STOP = "kill `#{PID}`"

# command to stop RT even if it refuses to stop
REALLY_STOP = "kill -9 `#{PID}`"

# command to check whether RT is running
RUNNING = "ps -e | grep #{BIN} | grep -v grep"

# command to obtain RT's current RAM usage in bytes
RAM = "ps -e -o rss,args | grep #{BIN} | grep -v grep | awk '{print $1}'"

# the maximum allowed rss size for RT
MAX_RAM = 128 * 1024 * 1024 # 128MB

def start
  `#{START}`
end

def stop
  begin
    Timeout::timeout 10 do
      `#{STOP}`
    end
  rescue Timeout::Error
    `#{REALLY_STOP}`
  end
end

def restart
  stop
  start
end

def ram
  `#{RAM}`.to_i
end

def running?
  `#{RUNNING}`.length > 0
end

def ram_too_big?
  ram > MAX_RAM
end

# main program
trap('TERM') do
  stop
  exit
end

loop do
  start unless running?
  restart if ram_too_big?
  sleep 2
end

/etc/init/rt-watchdog.conf

Also remove cached Mason data before starting up.

# rt-watchdog - Keep RT running
start on runlevel [12345]
stop on runlevel [0]

respawn

pre-start script
  rm -rf /opt/rt4/var/mason_data/obj
end script

exec /opt/rt4/bin/rt-watchdog
Posted in scripts | Tagged , , , , , | Leave a comment

Beyond setTimeout: Delay Your JavaScript with Closures

Have you ever wanted to delay something with JavaScript? So, of course, you look to window.setTimeout. But maybe this is interactive, or you want to be able to interrupt it? Then you save a reference to it, and you pass that reference around, and you lose track of it, and you get a headache and you go for a walk.

var myTimeout;  // ...because we have to use it in multiple contexts.
                // It's this or pass it as an argument to every function.
                // Both solutions are ugly.

function foo() {
  // do something fun
}

function waitATic() {
  myTimeout = setTimeout(foo, 5000);
}

function startOver() {
  clearTimeout(myTimeout);
  waitATic();
}

waitATic();

// then some stuff happens. Maybe we set up some event listeners and something
// triggers a...

startOver();

I don’t know. That looks like a lot of code to accomplish something as simple as, “Do this after a delay. If you’re interrupted, start over.”

Closures to the Rescue

Obviously, you don’t want to clutter up your context with variables that are really meant to track state inside a function. Maybe you could build an object with methods for handling and reporting its state as well as starting and stopping your timer. That still sounds like a lot of code… Maybe you could use a closure!

function foo() {
  // do something fun
}

function bar() {
  // do something really fun!
}

// Here comes that function with its closure!
// delay ends up a function which accepts 2 arguments
//     callback is the function to be executed after the delay
//     ms is the delay defined in milliseconds.
// If we call delay again, it actually clears the original timeout so that
// the callback isn't called twice!
var delay = (function() {
  var timeout = 0;
  return function(callback, ms) {
    clearTimeout(timeout);
    timeout = setTimeout(callback, ms);
  };
})();

delay(foo, 5000);

// then some stuff happens. Maybe an event is triggered and we start over...

delay(foo, 5000);

// and then maybe we want something else to happen on a delay. We can reuse
// that code!

delay(bar, 30000);

Remember that this function is stateful, so if you pass in another callback before your first one is called, it will get clobbered.

delay(foo, 2000); // foo will never run
delay(bar, 1000); // because bar will clobber it

Also, you can’t put callbacks in your callbacks with this implementation…

delay(function() {
  console.log('yo dawg');
  delay(function() {
    console.log('I heard you like callbacks');
  }, 2000);
}, 1000);

Only I heard you like callbacks is logged; yo dawg never happens.

Practical Applications

A very useful application of this delay function is in firing an event after user input. Say you’re doing some form field completion and you don’t want to sent an HTTP request after every keystroke. You can wait a small delay first. Check out this example which uses jQuery (and assumes that you’ve already written an updateAutoComplete function).

$('input#search').keyup(function() {
  delay(updateAutoComplete, 250);
});

Pretty cool, right?

Did you find this article helpful? Would you like to contribute a non-clobbering example? I’d love some feedback. Please leave a comment. :)

Posted in javascript | Tagged , , , , , , , , , | Leave a comment

Delete a Line from a File by Its Line Number

I keep having this problem. You know how ssh will tell you when the host’s keys have changed? For example, you try to ssh to example.org

$ ssh example.org

and you get

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that the RSA host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff.
Please contact your system administrator.
Add correct host key in /home/me/.ssh/known_hosts to get rid of this message.
Offending key in /home/me/.ssh/known_hosts:16
RSA host key for example.org has changed and you have requested strict checking.
Host key verification failed.

Well, you can

$ ssh-keygen -R example.org

But that doesn’t fix it completely. Try to connect again, and you may get something like

Warning: the ECDSA host key for 'example.org' differs from the key for the IP address '192.168.0.1'
Offending key for IP in /home/me/.ssh/known_hosts:17
Matching host key in /home/me/.ssh/known_hosts:19
Are you sure you want to continue connecting (yes/no)?

Dammit! I used to open this in a text editor and delete the offending line. But let’s think about this. It gives us the line number, and it’s a Unix system. Can’t we automate this?

Yep. Use sed. The offending line is 17? All we have to do is

$ sed -i 17d ~/.ssh/known_hosts

So sed edits the file in-line (-i), and deletes the 17th line (17d). Hooray!

Posted in fixes | Tagged , , , , , | 2 Comments

Running Rails 2.3.14 on Ruby 1.9.2

While trying to run Rails 2.3.14 on Ruby 1.9.2, I was getting an error page with

ActionView::TemplateError (invalid byte sequence in US-ASCII)

Turns out Rails 2.3.14 on Ruby 1.9.2 was trying to read my UTF-8 data as US-ASCII.

Solution

Don’t use Ruby 1.9.2. I’m serious. Use Ruby 1.8.7 (I use ree 1.8.7). Works fine. You can use a newer Ruby when you switch to Rails 3+. To keep track of your Ruby and Gem versions, use RVM. Be sure to check out rvm wrapper!

You’re welcome. :)

Posted in fixes | Tagged , , , , | Leave a comment

Run Wireshark as Non-Privileged User in Ubuntu

This has been annoying me for a while, so I researched it. I wrongfully submitted a bug to Launchpad, and finally was directed to an answer.

It was bugging me that there was no simple way to add a gksu wireshark shortcut in Unity. It turns out that that isn’t what you want to do. If you check your file:///usr/share/doc/wireshark-common/README.Debian, you’ll see that there is an extra step to being able to run Wireshark with full functionality as a non-root user. A quick summary:

  1. Install Wireshark as you normally would.
  2. Run sudo dpkg-reconfigure wireshark-common to enable capturing by non-priveleged users.
  3. Run sudo adduser myname wireshark to add yourself to the wireshark group.

That’s it. Obviously, replace myname with your username. You have to log out of your desktop session and log in again before it will work. But it works. :)

Posted in fixes | Tagged , , , , , , | Leave a comment

Augmenting Intelligence?

I read (most of) this book called What the Dormouse Said: How the Sixties Counterculture Shaped the Personal Computer Industry, and it discussed this really neat idea of computers as augmenting human intelligence. It’s not so much that we use these tools as it is that we integrate them into ourselves. Wikipedia on my cell phone is just another way of accessing knowledge. Instead of retrieving it from my brain, I’m retrieving it from our collective conscience. The quality of this information varies, but after enough peer review, it’s a much more reliable source of information than my own memory. In a way, it’s better than learning.

Of course the argument against this way of thinking is that by augmenting intelligence you weaken it, because you fail to acquire the inductive and deductive tools that acquiring knowledge through experience build for you. It makes sense that a generation of lazy thinkers would be show less creativity and ingenuity.

I think that we’re seeing both simultaneously. Unprecedented, rapid innovation is enabled; but so is lazy thinking. It all boils down to a socioeconomic issue (like everything else). Teach your people how to think and how to learn, and they’ll be able to employ those skills as adults and participate and contribute to the global community in a capacity perhaps a little deeper and more meaningful than YouTube comments.

Posted in editorials | Tagged , , , , | Leave a comment

Develop Multiple Websites by Adding Hosts File Entries

Background

I work on multiple websites. My workflow goes like this:

  1. Pull latest changes into my local repository (I use Git)
  2. Make changes
  3. Test changes on locally running web server
  4. Push changes to remote repository
  5. Pull changes into live site

The Problem

Webpages are complex. They source external scripts and stylesheets. What if a script is linked relative to the site root? If I put the site in a directory and access it at http://localhost/worksite, the link will break. The fix is obvious: put the site in the root, http://localhost/. But, as I said, I work on multiple sites. I guess I could run each site on a different port, but that’s gross.

My Solution

Used named virtualhosts and add hosts file records for them. So add a record like

127.0.0.1 worksite

to /etc/hosts (%SystemRoot%\system32\drivers\etc\hosts in Windows). Then add a virtualhost to your web server. In nginx, create a new site that looks like this:

server {
  listen worksite:80;
  server_name worksite;
  location / {
    root /home/force/web/worksite;
    index index.html;
  }
}

In Apache, your new site looks something like

<VirtualHost *:80>
  ServerName worksite
  DocumentRoot /home/force/web/worksite
</VirtualHost>

Restart your server, and you can access your site by going to http://worksite/. Simple and clean.

Posted in workflows | Tagged , , , , , , | Leave a comment

Vim up your Bash

Are you a CLI ninja? I write a lot of single-use, throwaway scripts in Bash. Usually, it’s an iterative process. But editing a long one-liner in Bash can be cumbersome if you’re also a Vim or Emacs ninja. So here’s a trick to pop that command that you’re working on into your default editor (Vim, in my case).

vi-style invocation

  1. If you haven’t already, add set -o vi to your .bashrc file so that every Bash instance uses vi-style editing.
  2. With the command you want to edit displayed, press ESC CTRL-\ v (lowercase v; press in order, not simultaneously).
  3. (Optional): As suggested by Jeet Sukumaran, you may want to add a keyboard shortcut for this. Append the following to your .bashrc to bind this behavior to CTRL-V:
# Ctrl-v: (insert mode) switch to command mode and edit in vi
bind '"\C-v": "\ev"'

Emacs-style invocation (Bash default)

  1. With the command you want to edit displayed, press CTRL-X CTRL-E (in order, not simultaneously).

Run the command (or don’t)

Either way, when you quit your editor, the modified command will be run by Bash. If you don’t want to run the command, quit without saving (:cq in Vim, CTRL-X CTRL-C in Emacs).

Posted in CLI | Tagged , , , , , | Leave a comment