jQuery sort_by plugin

Sometimes the ruby-style sort_by sorting is easier to use than JavaScripts default sort implementation.

Here’s a plugin that brings sort_by functionality to jQuery.

#! javascript
$.fn.sortBy = function(fn, options) {
  var opts = $.extend({ reverse: false }, options);
  return this.map(function(i, el) { return [[fn(el, i), el]]; }).sort(function(a, b) {
    return (a[0] == b[0] ? 0 : (a[0] > b[0] ? 1 : -1)) * (opts.reverse ? -1 : 1);
  }).map(function(i, ar) { return ar[1]; });
};

And here’s how you use it.

#! javascript
$trs.sortBy(function(tr) {
  return $(tr).find('.' + col).data('sort');
}, { reverse: $th.is('.desc') }).appendTo($tbody);

Check out the code on GitHub.

Create a reusable EC2 AMI from your instance

Here's how to bundle your running instance into its own AMI, in case you're wary of running your code on a server you didn't set up yourself.

Much of this post is based on Creating a New Image for EC2 by Rebundling a Running Instance from alestic.

Note: these instructions leave your ssh keys in the bundled AMI, and so are not appropriate for creating public AMIs.

These instructions assume you have set-up S3 in the manner described in the previous post.

bundle the instance

locally

copy your aws auth to the remote instance

> scp -r ~/.ec2 ec2-ubunutu:

on the remote machine

move the auth keys to /mnt/

> sudo mv .ec2 /mnt/

enable multiverse

> sudo sed -i.dist s/universe/multiverse/ /etc/apt/sources.list

install ec2-api-tools

> sudo apt-get install ec2-ami-tools
> sudo apt-get install ec2-api-tools

if you want to use the instance on micro, comment out the following line in /etc/fstab

> sudo vi /etc/fstab
# /dev/sda2 /mnt    auto    defaults,comment=cloudconfig    0   0

for the reason behind this, see

  1. http://stackoverflow.com/questions/3679156/ec2-small-to-micro-instance-downgrade-problems
  2. http://www.mail-archive.com/ubuntu-bugs@lists.ubuntu.com/msg2480051.html

setup environment variables

source /mnt/ec2/aws-keys
export EC2_PRIVATE_KEY=/mnt/ec2/pk-*.pem
export EC2_CERT=/mnt/ec2/cert-*.pem
export JAVA_HOME=/usr/lib/jvm/java-6-openjdk/

clean up after yourself before you save your tracks forever

> history -c && sudo rm -f /root/.*hist* /home/ubuntu/.*hist*

Bundle the files on the current instance into a copy of the image under /mnt note: this takes a while so you may want to run it under screen.

> sudo ec2-bundle-vol                   \
  -r i386                               \
  -k $EC2_PRIVATE_KEY                   \
  -c $EC2_CERT                          \
  -u $AWS_USER_ID                       \
  -d /mnt                               \
  -p myami                              \
  -e /mnt

Upload the bundle to a bucket on S3

> ec2-upload-bundle                 \
  -b myec2bucket     \
  -m /mnt/myami.manifest.xml  \
  -a $AWS_ACCESS_KEY_ID             \
  -s $AWS_SECRET_ACCESS_KEY

register the image as a new AMI.

> ec2-register                                             \
  --name myec2bucket/myami                                 \
  -K $EC2_PRIVATE_KEY                                      \
  -C $EC2_CERT                                             \
  myec2bucket/myami.manifest.xml

after the image is registered, you will see output like ami-1234de7b

create a new instance from the AMI

Just run the ami identified in the output from the above step with ec2-run-instances. It should be all set-up and ready to go.

> ec2-run-instances ami-98c035f1 --instance-type t1.micro --key mykeypair

A list of --instance-type options is available at http://docs.amazonwebservices.com/AWSEC2/latest/DeveloperGuide/

Getting Started with EC2

Getting started with EC2 isn't exactly trivial. Here's what I did to get up and running mostly using the command line.

set up your computer

on your local machine

go to the amazon web interface

note your AWS_USER_ID in the upper right hand corner. create a new AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY.

edit ~/.ec2/aws-keys

> vi ~/.ec2/aws-keys

and save the information

export AWS_USER_ID=XXXX-XXXX-XXXX
export AWS_ACCESS_KEY_ID=XXXXXXXXXXXXXXXXXXXX
export AWS_SECRET_ACCESS_KEY=xXxXXXxxXXXxXxxxXxxXXXXxXxXXxXxXxxXXxXxX

create a new X.509 certificate, download the private key and certificate files, and then save the files in $HOME/.ec2/

> mv ~/Downloads/*.pem ~/.ec2/

setup permissions on ~/.ec2

chmod 0600 ~/.ec2/*
chmod 0700 ~/.ec2

if needed, install the tools for working with ec2

> brew install ec2-api-tools
> brew install ec2-ami-tools

add the following lines to your .bash_profile

export JAVA_HOME="/System/Library/Frameworks/JavaVM.framework/Home"
export EC2_PRIVATE_KEY="$(/bin/ls $HOME/.ec2/pk-*.pem)"
export EC2_CERT="$(/bin/ls $HOME/.ec2/cert-*.pem)"
export EC2_AMITOOL_HOME="/usr/local/Cellar/ec2-ami-tools/1.3-45758/jars"
export EC2_HOME="/usr/local/Cellar/ec2-api-tools/1.3-53907/jars"
source $HOME/.ec2/aws-keys

open a new shell, or

> source ~/.bash_profile

if needed, create a new keypair for sever auth

> ec2-add-keypair mykeypair > mykeypair.pem
> chmod 0600 mykeypair.pem

copy that key to ~/.ec2/ as well

> cp mykeypair.pem ~/.ec2/

create the server

start-up a canonical provided ubuntu image (list of latest images available at: http://uec-images.ubuntu.com/releases/lucid/release/), here's the choice I made

  • us-east-1 - cheaper
  • 32-bit - more compatible, small and micro require it
  • ebs - simpler storage, micro requires it

note: we're setting up the instance on a small (rather than micro) platform because we need /mnt (not available on micro) to do the bundling. Once we have our new instance handy, we will move it to micro.

> ec2-run-instances ami-1234de7b --instance-type m1.small --region us-east-1 --key mykeypair

to run on micro instead, just change the instance type

> ec2-run-instances ami-1234de7b --instance-type t1.micro --region us-east-1 --key mykeypair

wait until it's running by watching ec2-describe-instances for the string running

> ec2-describe-instances

edit your ~/.ssh/config file to make it easy to ssh into the new instance note: the HostName and HostKeyAlias will change based on the output provided by ec2-describe-instances.

Host ec2-ubuntu
  HostName ec2-67-202-62-82.compute-1.amazonaws.com
  HostKeyAlias ec2-67-202-62-82.compute-1.amazonaws.com
  User ubuntu
  ForwardAgent yes
  StrictHostKeyChecking no
  IdentityFile ~/.ec2/mykeypair.pem

now you can ssh into your instance

> ssh ec2-ubuntu

note, for your instance on micro to survive a restart, you'll also need to comment out the following line in /etc/fstab

> sudo vi /etc/fstab
# /dev/sda2 /mnt    auto    defaults,comment=cloudconfig    0   0

for the reason behind this, see

  1. http://stackoverflow.com/questions/3679156/ec2-small-to-micro-instance-downgrade-problems
  2. http://www.mail-archive.com/ubuntu-bugs@lists.ubuntu.com/msg2480051.html

Installing Postgres intarray with Homebrew on a mac

The homebrew formula for postgres doesn't include intarray by default, so you need to include it.

cd /usr/local/Library/Formula/
cat <<EOD | git apply
diff --git a/Library/Formula/postgresql.rb b/Library/Formula/postgresql.rb
index bb526f3..4fd2d5a 100644
--- a/Library/Formula/postgresql.rb
+++ b/Library/Formula/postgresql.rb
@@ -51,6 +51,6 @@ class Postgresql <Formula
     system "make install"

     %w[ adminpack dblink fuzzystrmatch lo uuid-ossp pg_buffercache pg_trgm
-        pgcrypto tsearch2 vacuumlo xml2 ].each do |a|
+        pgcrypto tsearch2 vacuumlo xml2 intarray ].each do |a|
       system "cd contrib/#{a}; make install"
     end
EOD

Then brew install postgres (you may need to brew remove postgres if you already have it installed).

Start the server:

pg_ctl -D /usr/local/var/postgres -l /usr/local/var/postgres/server.log start

Then, install the commands into template1:

psql -f /usr/local/Cellar/postgresql/8.4.4/share/contrib/_int.sql template1

Note: in postgres, template1 is the database from which new databases are cloned. Hence, the above command will not install intarray into any existing databases, but it will be available on any newly created ones. You may manually install intarray on existing databases by changing template1 above to your existing database name.