aboutsummaryrefslogtreecommitdiffstats
path: root/signaling-server/node_modules/redis/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'signaling-server/node_modules/redis/README.md')
-rw-r--r--signaling-server/node_modules/redis/README.md744
1 files changed, 744 insertions, 0 deletions
diff --git a/signaling-server/node_modules/redis/README.md b/signaling-server/node_modules/redis/README.md
new file mode 100644
index 0000000..830cb57
--- /dev/null
+++ b/signaling-server/node_modules/redis/README.md
@@ -0,0 +1,744 @@
+redis - a node.js redis client
+===========================
+
+This is a complete Redis client for node.js. It supports all Redis commands, including many recently added commands like EVAL from
+experimental Redis server branches.
+
+
+Install with:
+
+ npm install redis
+
+Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do:
+
+ npm install hiredis redis
+
+If `hiredis` is installed, `node_redis` will use it by default. Otherwise, a pure JavaScript parser will be used.
+
+If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of node. There are mysterious failures that can
+happen between node and native code modules after a node upgrade.
+
+
+## Usage
+
+Simple example, included as `examples/simple.js`:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ // if you'd like to select database 3, instead of 0 (default), call
+ // client.select(3, function() { /* ... */ });
+
+ client.on("error", function (err) {
+ console.log("Error " + err);
+ });
+
+ client.set("string key", "string val", redis.print);
+ client.hset("hash key", "hashtest 1", "some value", redis.print);
+ client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
+ client.hkeys("hash key", function (err, replies) {
+ console.log(replies.length + " replies:");
+ replies.forEach(function (reply, i) {
+ console.log(" " + i + ": " + reply);
+ });
+ client.quit();
+ });
+```
+
+This will display:
+
+ mjr:~/work/node_redis (master)$ node example.js
+ Reply: OK
+ Reply: 0
+ Reply: 0
+ 2 replies:
+ 0: hashtest 1
+ 1: hashtest 2
+ mjr:~/work/node_redis (master)$
+
+
+## Performance
+
+Here are typical results of `multi_bench.js` which is similar to `redis-benchmark` from the Redis distribution.
+It uses 50 concurrent connections with no pipelining.
+
+JavaScript parser:
+
+ PING: 20000 ops 42283.30 ops/sec 0/5/1.182
+ SET: 20000 ops 32948.93 ops/sec 1/7/1.515
+ GET: 20000 ops 28694.40 ops/sec 0/9/1.740
+ INCR: 20000 ops 39370.08 ops/sec 0/8/1.269
+ LPUSH: 20000 ops 36429.87 ops/sec 0/8/1.370
+ LRANGE (10 elements): 20000 ops 9891.20 ops/sec 1/9/5.048
+ LRANGE (100 elements): 20000 ops 1384.56 ops/sec 10/91/36.072
+
+hiredis parser:
+
+ PING: 20000 ops 46189.38 ops/sec 1/4/1.082
+ SET: 20000 ops 41237.11 ops/sec 0/6/1.210
+ GET: 20000 ops 39682.54 ops/sec 1/7/1.257
+ INCR: 20000 ops 40080.16 ops/sec 0/8/1.242
+ LPUSH: 20000 ops 41152.26 ops/sec 0/3/1.212
+ LRANGE (10 elements): 20000 ops 36563.07 ops/sec 1/8/1.363
+ LRANGE (100 elements): 20000 ops 21834.06 ops/sec 0/9/2.287
+
+The performance of `node_redis` improves dramatically with pipelining, which happens automatically in most normal programs.
+
+
+### Sending Commands
+
+Each Redis command is exposed as a function on the `client` object.
+All functions take either an `args` Array plus optional `callback` Function or
+a variable number of individual arguments followed by an optional callback.
+Here is an example of passing an array of arguments and a callback:
+
+ client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {});
+
+Here is that same call in the second style:
+
+ client.mset("test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {});
+
+Note that in either form the `callback` is optional:
+
+ client.set("some key", "some val");
+ client.set(["some other key", "some val"]);
+
+If the key is missing, reply will be null (probably):
+
+ client.get("missingkey", function(err, reply) {
+ // reply is null when the key is missing
+ console.log(reply);
+ });
+
+For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands)
+
+The commands can be specified in uppercase or lowercase for convenience. `client.get()` is the same as `client.GET()`.
+
+Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings,
+integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a
+JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keyed by the hash keys.
+
+# API
+
+## Connection Events
+
+`client` will emit some events about the state of the connection to the Redis server.
+
+### "ready"
+
+`client` will emit `ready` a connection is established to the Redis server and the server reports
+that it is ready to receive commands. Commands issued before the `ready` event are queued,
+then replayed just before this event is emitted.
+
+### "connect"
+
+`client` will emit `connect` at the same time as it emits `ready` unless `client.options.no_ready_check`
+is set. If this options is set, `connect` will be emitted when the stream is connected, and then
+you are free to try to send commands.
+
+### "error"
+
+`client` will emit `error` when encountering an error connecting to the Redis server.
+
+Note that "error" is a special event type in node. If there are no listeners for an
+"error" event, node will exit. This is usually what you want, but it can lead to some
+cryptic error messages like this:
+
+ mjr:~/work/node_redis (master)$ node example.js
+
+ node.js:50
+ throw e;
+ ^
+ Error: ECONNREFUSED, Connection refused
+ at IOWatcher.callback (net:870:22)
+ at node.js:607:9
+
+Not very useful in diagnosing the problem, but if your program isn't ready to handle this,
+it is probably the right thing to just exit.
+
+`client` will also emit `error` if an exception is thrown inside of `node_redis` for whatever reason.
+It would be nice to distinguish these two cases.
+
+### "end"
+
+`client` will emit `end` when an established Redis server connection has closed.
+
+### "drain"
+
+`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now
+writable. This event can be used to stream commands in to Redis and adapt to backpressure. Right now,
+you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can
+resume sending when you get `drain`.
+
+### "idle"
+
+`client` will emit `idle` when there are no outstanding commands that are awaiting a response.
+
+## redis.createClient()
+
+### overloading
+* redis.createClient() = redis.createClient(6379, '127.0.0.1', {})
+* redis.createClient(options) = redis.createClient(6379, '127.0.0.1', options)
+* redis.createClient(unix_socket, options)
+* redis.createClient(port, host, options)
+
+If you have `redis-server` running on the same computer as node, then the defaults for
+port and host are probably fine. `options` in an object with the following possible properties:
+
+* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed.
+This may also be set to `javascript`.
+* `return_buffers`: defaults to `false`. If set to `true`, then all replies will be sent to callbacks as node Buffer
+objects instead of JavaScript Strings.
+* `detect_buffers`: default to `false`. If set to `true`, then replies will be sent to callbacks as node Buffer objects
+if any of the input arguments to the original command were Buffer objects.
+This option lets you switch between Buffers and Strings on a per-command basis, whereas `return_buffers` applies to
+every command on a client.
+* `socket_nodelay`: defaults to `true`. Whether to call setNoDelay() on the TCP stream, which disables the
+Nagle algorithm on the underlying socket. Setting this option to `false` can result in additional throughput at the
+cost of more latency. Most applications will want this set to `true`.
+* `socket_keepalive` defaults to `true`. Whether the keep-alive functionality is enabled on the underlying socket.
+* `no_ready_check`: defaults to `false`. When a connection is established to the Redis server, the server might still
+be loading the database from disk. While loading, the server not respond to any commands. To work around this,
+`node_redis` has a "ready check" which sends the `INFO` command to the server. The response from the `INFO` command
+indicates whether the server is ready for more commands. When ready, `node_redis` emits a `ready` event.
+Setting `no_ready_check` to `true` will inhibit this check.
+* `enable_offline_queue`: defaults to `true`. By default, if there is no active
+connection to the redis server, commands are added to a queue and are executed
+once the connection has been established. Setting `enable_offline_queue` to
+`false` will disable this feature and the callback will be execute immediately
+with an error, or an error will be thrown if no callback is specified.
+* `retry_max_delay`: defaults to `null`. By default every time the client tries to connect and fails time before
+reconnection (delay) almost doubles. This delay normally grows infinitely, but setting `retry_max_delay` limits delay
+to maximum value, provided in milliseconds.
+* `connect_timeout` defaults to `false`. By default client will try reconnecting until connected. Setting `connect_timeout`
+limits total time for client to reconnect. Value is provided in milliseconds and is counted once the disconnect occured.
+* `max_attempts` defaults to `null`. By default client will try reconnecting until connected. Setting `max_attempts`
+limits total amount of reconnects.
+* `auth_pass` defaults to `null`. By default client will try connecting without auth. If set, client will run redis auth command on connect.
+* `family` defaults to `IPv4`. The client connects in IPv4 if not specified or if the DNS resolution returns an IPv4 address.
+You can force an IPv6 if you set the family to 'IPv6'. See nodejs net or dns modules how to use the family type.
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient({detect_buffers: true});
+
+ client.set("foo_rand000000000000", "OK");
+
+ // This will return a JavaScript String
+ client.get("foo_rand000000000000", function (err, reply) {
+ console.log(reply.toString()); // Will print `OK`
+ });
+
+ // This will return a Buffer since original key is specified as a Buffer
+ client.get(new Buffer("foo_rand000000000000"), function (err, reply) {
+ console.log(reply.toString()); // Will print `<Buffer 4f 4b>`
+ });
+ client.end();
+```
+
+`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
+
+
+## client.auth(password, callback)
+
+When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the
+first command after connecting. This can be tricky to coordinate with reconnections, the ready check,
+etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection,
+including reconnections. `callback` is invoked only once, after the response to the very first
+`AUTH` command sent.
+NOTE: Your call to `client.auth()` should not be inside the ready handler. If
+you are doing this wrong, `client` will emit an error that looks
+something like this `Error: Ready check failed: ERR operation not permitted`.
+
+## client.end()
+
+Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed.
+If you want to exit cleanly, call `client.quit()` to send the `QUIT` command after you have handled all replies.
+
+This example closes the connection to the Redis server before the replies have been read. You probably don't
+want to do this:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ client.set("foo_rand000000000000", "some fantastic value");
+ client.get("foo_rand000000000000", function (err, reply) {
+ console.log(reply.toString());
+ });
+ client.end();
+```
+
+`client.end()` is useful for timeout cases where something is stuck or taking too long and you want
+to start over.
+
+## client.unref()
+
+Call `unref()` on the underlying socket connection to the Redis server, allowing the program to exit once no more commands are pending.
+
+This is an **experimental** feature, and only supports a subset of the Redis protocol. Any commands where client state is saved on the Redis server, e.g. `*SUBSCRIBE` or the blocking `BL*` commands will *NOT* work with `.unref()`.
+
+```js
+var redis = require("redis")
+var client = redis.createClient()
+
+/*
+ Calling unref() will allow this program to exit immediately after the get command finishes. Otherwise the client would hang as long as the client-server connection is alive.
+*/
+client.unref()
+client.get("foo", function (err, value){
+ if (err) throw(err)
+ console.log(value)
+})
+```
+
+## Friendlier hash commands
+
+Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings.
+When dealing with hash values, there are a couple of useful exceptions to this.
+
+### client.hgetall(hash)
+
+The reply from an HGETALL command will be converted into a JavaScript Object by `node_redis`. That way you can interact
+with the responses using JavaScript syntax.
+
+Example:
+
+ client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234");
+ client.hgetall("hosts", function (err, obj) {
+ console.dir(obj);
+ });
+
+Output:
+
+ { mjr: '1', another: '23', home: '1234' }
+
+### client.hmset(hash, obj, [callback])
+
+Multiple values in a hash can be set by supplying an object:
+
+ client.HMSET(key2, {
+ "0123456789": "abcdefghij", // NOTE: key and value will be coerced to strings
+ "some manner of key": "a type of value"
+ });
+
+The properties and values of this Object will be set as keys and values in the Redis hash.
+
+### client.hmset(hash, key1, val1, ... keyn, valn, [callback])
+
+Multiple values may also be set by supplying a list:
+
+ client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value");
+
+
+## Publish / Subscribe
+
+Here is a simple example of the API for publish / subscribe. This program opens two
+client connections, subscribes to a channel on one of them, and publishes to that
+channel on the other:
+
+```js
+ var redis = require("redis"),
+ client1 = redis.createClient(), client2 = redis.createClient(),
+ msg_count = 0;
+
+ client1.on("subscribe", function (channel, count) {
+ client2.publish("a nice channel", "I am sending a message.");
+ client2.publish("a nice channel", "I am sending a second message.");
+ client2.publish("a nice channel", "I am sending my last message.");
+ });
+
+ client1.on("message", function (channel, message) {
+ console.log("client1 channel " + channel + ": " + message);
+ msg_count += 1;
+ if (msg_count === 3) {
+ client1.unsubscribe();
+ client1.end();
+ client2.end();
+ }
+ });
+
+ client1.incr("did a thing");
+ client1.subscribe("a nice channel");
+```
+
+When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into a "subscriber" mode.
+At that point, only commands that modify the subscription set are valid. When the subscription
+set is empty, the connection is put back into regular mode.
+
+If you need to send regular commands to Redis while in subscriber mode, just open another connection.
+
+## Subscriber Events
+
+If a client has subscriptions active, it may emit these events:
+
+### "message" (channel, message)
+
+Client will emit `message` for every message received that matches an active subscription.
+Listeners are passed the channel name as `channel` and the message Buffer as `message`.
+
+### "pmessage" (pattern, channel, message)
+
+Client will emit `pmessage` for every message received that matches an active subscription pattern.
+Listeners are passed the original pattern used with `PSUBSCRIBE` as `pattern`, the sending channel
+name as `channel`, and the message Buffer as `message`.
+
+### "subscribe" (channel, count)
+
+Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are passed the
+channel name as `channel` and the new count of subscriptions for this client as `count`.
+
+### "psubscribe" (pattern, count)
+
+Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners are passed the
+original pattern as `pattern`, and the new count of subscriptions for this client as `count`.
+
+### "unsubscribe" (channel, count)
+
+Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners are passed the
+channel name as `channel` and the new count of subscriptions for this client as `count`. When
+`count` is 0, this client has left subscriber mode and no more subscriber events will be emitted.
+
+### "punsubscribe" (pattern, count)
+
+Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the
+channel name as `channel` and the new count of subscriptions for this client as `count`. When
+`count` is 0, this client has left subscriber mode and no more subscriber events will be emitted.
+
+## client.multi([commands])
+
+`MULTI` commands are queued up until an `EXEC` is issued, and then all commands are run atomically by
+Redis. The interface in `node_redis` is to return an individual `Multi` object by calling `client.multi()`.
+
+```js
+ var redis = require("./index"),
+ client = redis.createClient(), set_size = 20;
+
+ client.sadd("bigset", "a member");
+ client.sadd("bigset", "another member");
+
+ while (set_size > 0) {
+ client.sadd("bigset", "member " + set_size);
+ set_size -= 1;
+ }
+
+ // multi chain with an individual callback
+ client.multi()
+ .scard("bigset")
+ .smembers("bigset")
+ .keys("*", function (err, replies) {
+ // NOTE: code in this callback is NOT atomic
+ // this only happens after the the .exec call finishes.
+ client.mget(replies, redis.print);
+ })
+ .dbsize()
+ .exec(function (err, replies) {
+ console.log("MULTI got " + replies.length + " replies");
+ replies.forEach(function (reply, index) {
+ console.log("Reply " + index + ": " + reply.toString());
+ });
+ });
+```
+
+### Multi.exec( callback )
+
+`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects share all of the
+same command methods as `client` objects do. Commands are queued up inside the `Multi` object
+until `Multi.exec()` is invoked.
+
+The `callback` of `.exec()` will get invoked with two arguments:
+
+* `err` **type:** `null | Array` err is either null or an array of Error Objects corresponding the the sequence the commands where chained. The last item of the array will always be an `EXECABORT` type of error originating from the `.exec()` itself.
+* `results` **type:** `null | Array` results is an array of responses corresponding the the sequence the commands where chained.
+
+You can either chain together `MULTI` commands as in the above example, or you can queue individual
+commands while still sending regular client command as in this example:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient(), multi;
+
+ // start a separate multi command queue
+ multi = client.multi();
+ multi.incr("incr thing", redis.print);
+ multi.incr("incr other thing", redis.print);
+
+ // runs immediately
+ client.mset("incr thing", 100, "incr other thing", 1, redis.print);
+
+ // drains multi queue and runs atomically
+ multi.exec(function (err, replies) {
+ console.log(replies); // 101, 2
+ });
+
+ // you can re-run the same transaction if you like
+ multi.exec(function (err, replies) {
+ console.log(replies); // 102, 3
+ client.quit();
+ });
+```
+
+In addition to adding commands to the `MULTI` queue individually, you can also pass an array
+of commands and arguments to the constructor:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient(), multi;
+
+ client.multi([
+ ["mget", "multifoo", "multibar", redis.print],
+ ["incr", "multifoo"],
+ ["incr", "multibar"]
+ ]).exec(function (err, replies) {
+ console.log(replies);
+ });
+```
+
+
+## Monitor mode
+
+Redis supports the `MONITOR` command, which lets you see all commands received by the Redis server
+across all client connections, including from other client libraries and other computers.
+
+After you send the `MONITOR` command, no other commands are valid on that connection. `node_redis`
+will emit a `monitor` event for every new monitor message that comes across. The callback for the
+`monitor` event takes a timestamp from the Redis server and an array of command arguments.
+
+Here is a simple example:
+
+```js
+ var client = require("redis").createClient(),
+ util = require("util");
+
+ client.monitor(function (err, res) {
+ console.log("Entering monitoring mode.");
+ });
+
+ client.on("monitor", function (time, args) {
+ console.log(time + ": " + util.inspect(args));
+ });
+```
+
+# Extras
+
+Some other things you might like to know about.
+
+## client.server_info
+
+After the ready probe completes, the results from the INFO command are saved in the `client.server_info`
+object.
+
+The `versions` key contains an array of the elements of the version string for easy comparison.
+
+ > client.server_info.redis_version
+ '2.3.0'
+ > client.server_info.versions
+ [ 2, 3, 0 ]
+
+## redis.print()
+
+A handy callback function for displaying return values when testing. Example:
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ client.on("connect", function () {
+ client.set("foo_rand000000000000", "some fantastic value", redis.print);
+ client.get("foo_rand000000000000", redis.print);
+ });
+```
+
+This will print:
+
+ Reply: OK
+ Reply: some fantastic value
+
+Note that this program will not exit cleanly because the client is still connected.
+
+## redis.debug_mode
+
+Boolean to enable debug mode and protocol tracing.
+
+```js
+ var redis = require("redis"),
+ client = redis.createClient();
+
+ redis.debug_mode = true;
+
+ client.on("connect", function () {
+ client.set("foo_rand000000000000", "some fantastic value");
+ });
+```
+
+This will display:
+
+ mjr:~/work/node_redis (master)$ node ~/example.js
+ send command: *3
+ $3
+ SET
+ $20
+ foo_rand000000000000
+ $20
+ some fantastic value
+
+ on_data: +OK
+
+`send command` is data sent into Redis and `on_data` is data received from Redis.
+
+## Multi-word commands
+
+To execute redis multi-word commands like `SCRIPT LOAD` or `CLIENT LIST` pass
+the second word as first parameter:
+
+ client.script('load', 'return 1');
+ client.multi().script('load', 'return 1').exec(...);
+ client.multi([['script', 'load', 'return 1']]).exec(...);
+
+## client.send_command(command_name, args, callback)
+
+Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis
+Wiki have been added to the `client` object. However, if I missed any, or if new commands are introduced before
+this library is updated, you can use `send_command()` to send arbitrary commands to Redis.
+
+All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or omitted.
+
+## client.connected
+
+Boolean tracking the state of the connection to the Redis server.
+
+## client.command_queue.length
+
+The number of commands that have been sent to the Redis server but not yet replied to. You can use this to
+enforce some kind of maximum queue depth for commands while connected.
+
+Don't mess with `client.command_queue` though unless you really know what you are doing.
+
+## client.offline_queue.length
+
+The number of commands that have been queued up for a future connection. You can use this to enforce
+some kind of maximum queue depth for pre-connection commands.
+
+## client.retry_delay
+
+Current delay in milliseconds before a connection retry will be attempted. This starts at `250`.
+
+## client.retry_backoff
+
+Multiplier for future retry timeouts. This should be larger than 1 to add more time between retries.
+Defaults to 1.7. The default initial connection retry is 250, so the second retry will be 425, followed by 723.5, etc.
+
+### Commands with Optional and Keyword arguments
+
+This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset count]` in the [redis.io/commands](http://redis.io/commands) documentation.
+
+Example:
+```js
+var args = [ 'myzset', 1, 'one', 2, 'two', 3, 'three', 99, 'ninety-nine' ];
+client.zadd(args, function (err, response) {
+ if (err) throw err;
+ console.log('added '+response+' items.');
+
+ // -Infinity and +Infinity also work
+ var args1 = [ 'myzset', '+inf', '-inf' ];
+ client.zrevrangebyscore(args1, function (err, response) {
+ if (err) throw err;
+ console.log('example1', response);
+ // write your code here
+ });
+
+ var max = 3, min = 1, offset = 1, count = 2;
+ var args2 = [ 'myzset', max, min, 'WITHSCORES', 'LIMIT', offset, count ];
+ client.zrevrangebyscore(args2, function (err, response) {
+ if (err) throw err;
+ console.log('example2', response);
+ // write your code here
+ });
+});
+```
+
+## TODO
+
+Better tests for auth, disconnect/reconnect, and all combinations thereof.
+
+Stream large set/get values into and out of Redis. Otherwise the entire value must be in node's memory.
+
+Performance can be better for very large values.
+
+I think there are more performance improvements left in there for smaller values, especially for large lists of small values.
+
+## How to Contribute
+- open a pull request and then wait for feedback (if
+ [DTrejo](http://github.com/dtrejo) does not get back to you within 2 days,
+ comment again with indignation!)
+
+## Contributors
+Some people have have added features and fixed bugs in `node_redis` other than me.
+
+Ordered by date of first contribution.
+[Auto-generated](http://github.com/dtrejo/node-authors) on Wed Jul 25 2012 19:14:59 GMT-0700 (PDT).
+
+- [Matt Ranney aka `mranney`](https://github.com/mranney)
+- [Tim-Smart aka `tim-smart`](https://github.com/tim-smart)
+- [Tj Holowaychuk aka `visionmedia`](https://github.com/visionmedia)
+- [rick aka `technoweenie`](https://github.com/technoweenie)
+- [Orion Henry aka `orionz`](https://github.com/orionz)
+- [Aivo Paas aka `aivopaas`](https://github.com/aivopaas)
+- [Hank Sims aka `hanksims`](https://github.com/hanksims)
+- [Paul Carey aka `paulcarey`](https://github.com/paulcarey)
+- [Pieter Noordhuis aka `pietern`](https://github.com/pietern)
+- [nithesh aka `nithesh`](https://github.com/nithesh)
+- [Andy Ray aka `andy2ray`](https://github.com/andy2ray)
+- [unknown aka `unknowdna`](https://github.com/unknowdna)
+- [Dave Hoover aka `redsquirrel`](https://github.com/redsquirrel)
+- [Vladimir Dronnikov aka `dvv`](https://github.com/dvv)
+- [Umair Siddique aka `umairsiddique`](https://github.com/umairsiddique)
+- [Louis-Philippe Perron aka `lp`](https://github.com/lp)
+- [Mark Dawson aka `markdaws`](https://github.com/markdaws)
+- [Ian Babrou aka `bobrik`](https://github.com/bobrik)
+- [Felix Geisendörfer aka `felixge`](https://github.com/felixge)
+- [Jean-Hugues Pinson aka `undefined`](https://github.com/undefined)
+- [Maksim Lin aka `maks`](https://github.com/maks)
+- [Owen Smith aka `orls`](https://github.com/orls)
+- [Zachary Scott aka `zzak`](https://github.com/zzak)
+- [TEHEK Firefox aka `TEHEK`](https://github.com/TEHEK)
+- [Isaac Z. Schlueter aka `isaacs`](https://github.com/isaacs)
+- [David Trejo aka `DTrejo`](https://github.com/DTrejo)
+- [Brian Noguchi aka `bnoguchi`](https://github.com/bnoguchi)
+- [Philip Tellis aka `bluesmoon`](https://github.com/bluesmoon)
+- [Marcus Westin aka `marcuswestin2`](https://github.com/marcuswestin2)
+- [Jed Schmidt aka `jed`](https://github.com/jed)
+- [Dave Peticolas aka `jdavisp3`](https://github.com/jdavisp3)
+- [Trae Robrock aka `trobrock`](https://github.com/trobrock)
+- [Shankar Karuppiah aka `shankar0306`](https://github.com/shankar0306)
+- [Ignacio Burgueño aka `ignacio`](https://github.com/ignacio)
+
+Thanks.
+
+## LICENSE - "MIT License"
+
+Copyright (c) 2010 Matthew Ranney, http://ranney.com/
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+![spacer](http://ranney.com/1px.gif)