[
  {
    "path": ".gitignore",
    "content": "node_modules\nnpm-debug.log\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\n\nlanguage: node_js\n\nnode_js:\n  - stable\n\nservices:\n  - redis-server\n\nafter_script:\n  - npm test\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2016 Chris O'Hara <cohara87@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# Redback\n\n[![NPM version][npm-image]][npm-url]\n[![Build Status][travis-image]][travis-url]\n[![Downloads][downloads-image]][npm-url]\n\nA high-level Redis library.\n\n```sh\n$ npm install redback\n```\n\n## Introduction\n\nRedback provides an accessible and extensible interface to the Redis\n[data types](http://redis.io/topics/data-types) and allows you to create\nyour own structures with ease. Redback comes with the following built-in\nstructures: **List**,  **Set**, **SortedSet**, **Hash**, **Channel**, **Cache**\n\nIt also comes with the following advanced data structures:\n\n- **DensitySet** - A sorted set where adding an element increments its score and removing it decrements it\n- **KeyPair** - Uses two hash structures and an auto-incrementing key to assign an ID to each unique value\n- **SocialGraph** - Similar to Twitter's (following vs. followers)\n- **CappedList** - A list with a fixed length\n- **Queue** - A simple FIFO or LIFO queue\n- **RateLimit** - Count the number of times an event occurs over an interval. See [this introduction](https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da).\n- **BloomFilter** - A probabilistic structure used to test whether an an element exists in a set\n\n## Usage\n\n```javascript\nvar redback = require('redback').createClient();\n\n// or\n\nvar redis = require('redis').createClient();\nvar redback = require('redback').use(redis);\n```\n\n```javascript\nvar user3 = redback.createSocialGraph(3);\nuser3.follow(1, callback);\n\nvar log = redback.createCappedList('log', 1000);\nlog.push('Log message ...');\n\nvar user = redback.createHash('user1');\nuser.set({username: 'chris', password: 'foobar'}, callback);\n```\n\n## Creating your own structures\n\nUse `addStructure(name, methods)` to create your own structure.\n\nLet's create a queue that can be either FIFO or LIFO:\n\n```javascript\nredback.addStructure('SimpleQueue', {\n    init: function (options) {\n        options = options || {};\n        this.fifo = options.fifo;\n    },\n    add: function (value, callback) {\n        this.client.lpush(this.key, value, callback);\n    },\n    next: function (callback) {\n        var method = this.fifo ? 'rpop' : 'lpop';\n        this.client[method](this.key, callback);\n    }\n});\n```\n\nCall `createSimpleQueue(key, options)` to use the queue:\n\n```javascript\nvar queue = redback.createSimpleQueue('my_queue', {fifo: true});\nqueue.add('awesome!');\n```\n\nStructures have access to a Redis key `this.key` and the Redis client\n`this.client`. If an `init()` method is defined then it is called after\nthe structure is instantiated. Also note that `init()` receives any extra parameters\nfrom `create<structure>()`.\n\n## Other uses\n\n**Cache backend**\n\n```javascript\nvar cache = redback.createCache(namespace);\ncache.set('foo', 'bar', callback);\ncache.get('foo', function (err, foo) {\n    console.log(foo); //bar\n});\n```\n\n**Pub/sub provider**\n\n```javascript\nvar channel = redback.createChannel('chat').subscribe();\n\n//To received messages\nchannel.on('message', function (msg) {\n   console.log(msg);\n});\n\n//To send messages\nchannel.publish(msg);\n```\n\n## Documentation\n\nSee the [annotated source](http://chriso.github.io/redback/api.html).\n\n## Tests\n\nThe tests require a local redis instance running on `localhost:6379`. Note that\nredis database #11 will be flushed prior to each run.\n\n```sh\n$ npm test\n```\n\n## Credits\n\n- Matt Ranney for his [node_redis](https://github.com/mranney/node_redis) library.\n- GitHub user [sreeix](https://github.com/sreeix) for the bloom filter implementation.\n\n## License\n\nMIT\n\n\n[downloads-image]: http://img.shields.io/npm/dm/redback.svg\n[npm-url]: https://npmjs.org/package/redback\n[npm-image]: http://img.shields.io/npm/v/redback.svg\n[travis-url]: https://travis-ci.org/chriso/redback\n[travis-image]: http://img.shields.io/travis/chriso/redback.svg\n"
  },
  {
    "path": "docs/api.html",
    "content": "<a href=\"https://github.com/chriso/redback\"><img alt=\"Fork me on GitHub\" id=\"ribbon\" src=\"http://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png\"></a><html>\n\t<head>\n\t\t<title>Redback</title>\n\t\t<script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js\"></script>\n\t\t<style>body {\n    margin: 0;\n    padding: 0;\n    font: 14px/1.5 'Palatino Linotype', 'Book Antiqua', Palatino, FreeSerif, serif;\n    color: #252519;\n}\na {\n    color: #252519;\n}\na:hover {\n    text-decoration: underline;\n    color: #19469D;\n}\np {\n    margin: 12px 0;\n}\nh1, h2, h3 {\n    margin: 0;\n    padding: 0;\n}\ntable#source {\n    width: 100%;\n    border-collapse: collapse;\n}\ntable#source td:first-child {\n    padding: 30px 40px 30px 40px;\n    vertical-align: top;\n}\ntable#source td:first-child,\ntable#source td:first-child pre {\n    width: 450px;\n}\ntable#source td:last-child {\n    padding: 30px 0 30px 40px;\n    border-left: 1px solid #E5E5EE;\n    background: #F5F5FF;\n}\ntable#source tr {\n    border-bottom: 1px solid #E5E5EE;\n}\ntable#source tr.filename {\n    padding-top: 40px;\n    border-top: 1px solid #E5E5EE;\n}\ntable#source tr.filename td:first-child {\n    text-transform: capitalize;\n}\ntable#source tr.filename td:last-child {\n    font-size: 12px;\n}\ntable#source tr.filename h2 {\n    margin: 0;\n    padding: 0;\n    cursor: pointer;\n}\ntable#source tr.code h1,\ntable#source tr.code h2,\ntable#source tr.code h3 {\n    margin-top: 30px;\n    font-family: \"Lucida Grande\", \"Helvetica Nueue\", Arial, sans-serif;\n    font-size: 18px;\n}\ntable#source tr.code h2 {\n    font-size: 16px;\n}\ntable#source tr.code h3 {\n    font-size: 14px;\n}\ntable#source tr.code ul {\n    margin: 15px 0 15px 35px;\n    padding: 0;\n}\ntable#source tr.code ul li {\n    margin: 0;\n    padding: 1px 0;\n}\ntable#source tr.code ul li p {\n    margin: 0;\n    padding: 0;\n}\ntable#source tr.code td:first-child pre {\n    padding: 20px;\n}\n#ribbon {\n    position: fixed;\n    top: 0;\n    right: 0;\n}\ncode .string { color: #219161; }\ncode .regexp { color: #219161; }\ncode .keyword { color: #954121; }\ncode .number { color: #19469D; }\ncode .comment { color: #bbb; }\ncode .this { color: #19469D; }</style>\n\t\t<script>\n\t\t\t$(function(){\n\t\t\t\t$('tr.code').hide();\n\t\t\t\t$('tr.filename').toggle(function(){\n\t\t\t\t\t$(this).nextUntil('.filename').fadeIn();\n\t\t\t\t}, function(){\n\t\t\t\t\t$(this).nextUntil('.filename').fadeOut();\n\t\t\t\t});\n\t\t\t});\n\t\t</script>\n\t</head>\n\t<body>\n<table id=\"source\"><tbody><tr><td><h1>Redback</h1><p>A high-level Redis library</p></td><td></td></tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/BloomFilter.js\"><a href=\"#\">BloomFilter</a></h2></td><td>lib/advanced_structures/BloomFilter.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>),\n    <span class=\"variable\">crc32</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Utils'</span>).<span class=\"variable\">crc32</span>;</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A Simple BloomFilter. Bloomfilter is a probabilistic data structure used to\ndetermine if an element is present in a set. There may be false positives,\nbut there cannot be false negatives.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createBloomFilter(key [, size, hashes]);</code></p>\n\n<h2>Options</h2>\n\n<p>   <code>size</code> - Size of the bloom filter , default is 100 bits.\n   <code>hashes</code> - Number of hashes to perform. default is 2.</p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/commands#string\n   http://en.wikipedia.org/wiki/Bloom_filter\n   http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = string(bits)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">BloomFilter</span> = <span class=\"variable\">exports</span>.<span class=\"class\">BloomFilter</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Adds an element to the bloom filter.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  item - Item to store into bloom filter</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">BloomFilter</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span>(<span class=\"variable\">item</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>(), <span class=\"variable\">crc</span>;\n\n    <span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> <span class=\"variable\">hash_index</span> = <span class=\"number integer\">0</span>; <span class=\"variable\">hash_index</span> &<span class=\"variable\">lt</span>; <span class=\"this\">this</span>.<span class=\"variable\">num_hashes</span>; <span class=\"variable\">hash_index</span>++) {\n        <span class=\"variable\">crc</span> = <span class=\"variable\">crc32</span>(<span class=\"variable\">item</span>, <span class=\"variable\">hash_index</span>) % (<span class=\"this\">this</span>.<span class=\"variable\">size</span>+<span class=\"number integer\">1</span>);\n        <span class=\"variable\">multi</span>.<span class=\"variable\">setbit</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">crc</span>, <span class=\"number integer\">1</span>);\n    }\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {});\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Checks if the element exists in the bloom filter. \nThis can return false positives( i.e An element does not exist but it returns true)\nBut this can never return false negatives. (i.e an element )</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  item - Item to check for existence in bloom filter</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">BloomFilter</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">exists</span> = <span class=\"keyword\">function</span>(<span class=\"variable\">item</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>(), <span class=\"variable\">crc</span>;\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n\n    <span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> <span class=\"variable\">hash_index</span> = <span class=\"number integer\">0</span>; <span class=\"variable\">hash_index</span> &<span class=\"variable\">lt</span>; <span class=\"this\">this</span>.<span class=\"variable\">num_hashes</span>; <span class=\"variable\">hash_index</span>++) {\n        <span class=\"variable\">crc</span> = <span class=\"variable\">crc32</span>(<span class=\"variable\">item</span>, <span class=\"variable\">hash_index</span>) % (<span class=\"this\">this</span>.<span class=\"variable\">size</span>+<span class=\"number integer\">1</span>);\n        <span class=\"variable\">multi</span>.<span class=\"variable\">getbit</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">crc</span>);\n    }\n\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"keyword\">function</span>(<span class=\"variable\">err</span>, <span class=\"variable\">results</span>) {\n        <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"variable\">results</span>.<span class=\"variable\">indexOf</span>(<span class=\"number integer\">0</span>) === -<span class=\"number integer\">1</span>);\n    });\n\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Resets the Bloom filter.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">BloomFilter</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">reset</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">set</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"number integer\">0</span>, <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {});\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/CappedList.js\"><a href=\"#\">CappedList</a></h2></td><td>lib/advanced_structures/CappedList.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">List</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../base_structures/List'</span>).<span class=\"class\">List</span>;</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A Redis list with a fixed length. Each command that adds a value to the\nlist is followed by an <code>LTRIM</code> command.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createCappedList(key [, max_length]);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#lists\n   http://redis.io/commands/ltrim</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = list(values)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">CappedList</span> = <span class=\"variable\">exports</span>.<span class=\"class\">CappedList</span> = <span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">extend</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Insert an element before the specified pivot.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  pivot</p></li><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">CappedList</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">insertBefore</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>()\n    <span class=\"variable\">multi</span>.<span class=\"variable\">linsert</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"string\">'BEFORE'</span>, <span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>);\n    <span class=\"variable\">multi</span>.<span class=\"variable\">ltrim</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, -<span class=\"number integer\">1</span> * <span class=\"this\">this</span>.<span class=\"variable\">len</span>, -<span class=\"number integer\">1</span>);\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Insert an element after the specified pivot.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  pivot</p></li><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">CappedList</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">insertAfter</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>()\n    <span class=\"variable\">multi</span>.<span class=\"variable\">linsert</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"string\">'AFTER'</span>, <span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>);\n    <span class=\"variable\">multi</span>.<span class=\"variable\">ltrim</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, -<span class=\"number integer\">1</span> * <span class=\"this\">this</span>.<span class=\"variable\">len</span>, -<span class=\"number integer\">1</span>);\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the start of the list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | array</em>  value(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">CappedList</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">unshift</span> = <span class=\"class\">CappedList</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">lpush</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>();\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">values</span>)) {\n        <span class=\"keyword\">var</span> <span class=\"variable\">key</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span>;\n        <span class=\"variable\">values</span>.<span class=\"variable\">reverse</span>().<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">value</span>) {\n            <span class=\"variable\">multi</span>.<span class=\"variable\">lpush</span>(<span class=\"variable\">key</span>, <span class=\"variable\">value</span>);\n        });\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">multi</span>.<span class=\"variable\">lpush</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">values</span>);\n    }\n    <span class=\"variable\">multi</span>.<span class=\"variable\">ltrim</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, -<span class=\"number integer\">1</span> * <span class=\"this\">this</span>.<span class=\"variable\">len</span>, -<span class=\"number integer\">1</span>);\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the end of the list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | array</em>  value(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">CappedList</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">push</span> = <span class=\"class\">CappedList</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>();\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">values</span>)) {\n        <span class=\"keyword\">var</span> <span class=\"variable\">key</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span>;\n        <span class=\"variable\">values</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">value</span>) {\n            <span class=\"variable\">multi</span>.<span class=\"variable\">rpush</span>(<span class=\"variable\">key</span>, <span class=\"variable\">value</span>);\n        });\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">multi</span>.<span class=\"variable\">rpush</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">values</span>);\n    }\n    <span class=\"variable\">multi</span>.<span class=\"variable\">ltrim</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, -<span class=\"number integer\">1</span> * <span class=\"this\">this</span>.<span class=\"variable\">len</span>, -<span class=\"number integer\">1</span>);\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/DensitySet.js\"><a href=\"#\">DensitySet</a></h2></td><td>lib/advanced_structures/DensitySet.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">SortedSet</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../base_structures/SortedSet'</span>).<span class=\"class\">SortedSet</span>;</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>The DensitySet is similar to a SortedSet but the ability to explicitly\nset an element's score has been removed. Instead, adding/removing\nan element will increment/decrement its score, e.g.\n    <code>DensitySet.add(['foo','foo','foo'], ..)</code> //'foo' has a score of 3</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createDensitySet(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#sorted-sets</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = zset(count =&gt; element)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">DensitySet</span> = <span class=\"variable\">exports</span>.<span class=\"class\">DensitySet</span> = <span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">extend</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  element(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">DensitySet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">element</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">addAll</span>(<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zincrby</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"number integer\">1</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove one or more elements from the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  element(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">DensitySet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">remove</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">element</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">removeAll</span>(<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zincrby</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, -<span class=\"number integer\">1</span>, <span class=\"variable\">element</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">removed</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n        <span class=\"variable\">self</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zremrangebyscore</span>(<span class=\"variable\">self</span>.<span class=\"variable\">key</span>, <span class=\"string\">'-inf'</span>, <span class=\"number integer\">0</span>, <span class=\"variable\">callback</span>);\n    });\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/KeyPair.js\"><a href=\"#\">KeyPair</a></h2></td><td>lib/advanced_structures/KeyPair.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>The KeyPair is a structure where unique values are assigned an\nID (like a table with a primary auto-incrementing key and\na single unique column). Internally, the KeyPair uses two Redis\nhashes to provide O(1) lookup by both ID and value.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createKeyPair(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#hashes</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key     = hash(id =&gt; value)</code>\n   <code>(namespace:)key:ids = hash(value =&gt; id)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">KeyPair</span> = <span class=\"variable\">exports</span>.<span class=\"class\">KeyPair</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add a unique value to the KeyPair and return its id. If the value already\nexists, the existing id is returned.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  value(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"comment\">//Pass on an array of values to addAll()</span>\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">value</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">addAll</span>(<span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    }\n\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>, <span class=\"variable\">hashed_value</span> = <span class=\"this\">this</span>.<span class=\"variable\">hashValue</span>(<span class=\"variable\">value</span>);\n    <span class=\"comment\">//Check if the value already has an id</span>\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"this\">this</span>.<span class=\"variable\">idkey</span>, <span class=\"variable\">value</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">id</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n        <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> !== <span class=\"variable\">id</span>) {\n            <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">id</span>);\n        } <span class=\"keyword\">else</span> {\n            <span class=\"comment\">//If not, create a new id</span>\n            <span class=\"variable\">self</span>.<span class=\"variable\">autoincrement</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">id</span>) {\n                <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n\n                <span class=\"comment\">//Set the id and value simultaneously</span>\n                <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"variable\">self</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>();\n                <span class=\"variable\">multi</span>.<span class=\"variable\">hsetnx</span>(<span class=\"variable\">self</span>.<span class=\"variable\">idkey</span>, <span class=\"variable\">hashed_value</span>, <span class=\"variable\">id</span>);\n                <span class=\"variable\">multi</span>.<span class=\"variable\">hsetnx</span>(<span class=\"variable\">self</span>.<span class=\"variable\">key</span>, <span class=\"variable\">id</span>, <span class=\"variable\">value</span>);\n                <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"keyword\">function</span>(<span class=\"variable\">err</span>, <span class=\"variable\">response</span>) {\n                    <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n\n                    <span class=\"comment\">//Another client may have add at exactly the same time, so do</span>\n                    <span class=\"comment\">//another get to get the actual stored id</span>\n                    <span class=\"variable\">self</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"variable\">self</span>.<span class=\"variable\">idkey</span>, <span class=\"variable\">hashed_value</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">real_id</span>) {\n                        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n                        <span class=\"keyword\">if</span> (<span class=\"variable\">real_id</span> == <span class=\"variable\">id</span>) {\n                            <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">real_id</span>);\n                        } <span class=\"keyword\">else</span> {\n                            <span class=\"comment\">//Another client did beat us! remove the bad key</span>\n                            <span class=\"variable\">self</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hdel</span>(<span class=\"variable\">self</span>.<span class=\"variable\">key</span>, <span class=\"variable\">id</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>) {\n                                <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n                                    <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n                                } <span class=\"keyword\">else</span> {\n                                    <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">real_id</span>);\n                                }\n                            });\n                        }\n                    });\n                });\n            });\n        }\n    });\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add multiple unique values to the KeyPair and return and\nobject containing {value: id, ...}.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Array</em>  values</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">addAll</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>,\n        <span class=\"variable\">remaining</span> = <span class=\"variable\">values</span>.<span class=\"variable\">length</span>,\n        <span class=\"variable\">ids</span> = {},\n        <span class=\"variable\">failed</span> = <span class=\"variable\">false</span>;\n\n    <span class=\"variable\">values</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">value</span>) {\n        <span class=\"variable\">self</span>.<span class=\"variable\">add</span>(<span class=\"variable\">value</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">id</span>) {\n            <span class=\"keyword\">if</span> (<span class=\"variable\">failed</span>) {\n                <span class=\"keyword\">return</span>;\n            } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n                <span class=\"variable\">failed</span> = <span class=\"variable\">true</span>;\n                <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n            } <span class=\"keyword\">else</span> {\n                <span class=\"variable\">ids</span>[<span class=\"variable\">value</span>] = <span class=\"variable\">id</span>;\n                <span class=\"keyword\">if</span> (!--<span class=\"variable\">remaining</span>) <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">ids</span>);\n            }\n        });\n    });\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Lookup a unique value and get the associated id.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">get</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">value</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">value</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hgetall</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">value</span>)) {\n        <span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> <span class=\"variable\">i</span> = <span class=\"number integer\">0</span>, <span class=\"variable\">l</span> = <span class=\"variable\">value</span>.<span class=\"variable\">length</span>; <span class=\"variable\">i</span> &<span class=\"variable\">lt</span>; <span class=\"variable\">l</span>; <span class=\"variable\">i</span>++) {\n            <span class=\"variable\">value</span>[<span class=\"variable\">i</span>] = <span class=\"this\">this</span>.<span class=\"variable\">hashValue</span>(<span class=\"variable\">value</span>[<span class=\"variable\">i</span>]);\n        }\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hmget</span>(<span class=\"this\">this</span>.<span class=\"variable\">idkey</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>)\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"this\">this</span>.<span class=\"variable\">idkey</span>, <span class=\"this\">this</span>.<span class=\"variable\">hashValue</span>(<span class=\"variable\">value</span>), <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the value associated with the id.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int | Array</em>  id(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getById</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">id</span>, <span class=\"variable\">callback</span>) {\n\t<span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">id</span>))\n    \t<span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hmget</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">id</span>, <span class=\"variable\">callback</span>);\n\t<span class=\"keyword\">else</span>\n    \t<span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">id</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get an array of ids.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">ids</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hkeys</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get an array of values.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">values</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hvals</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Check whether a unique value already exists and  has an associated id.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">exists</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hexists</span>(<span class=\"this\">this</span>.<span class=\"variable\">idkey</span>, <span class=\"this\">this</span>.<span class=\"variable\">hashValue</span>(<span class=\"variable\">value</span>), <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Checks whether an id exists.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">idExists</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">id</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hexists</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">id</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Deletes a unique value and its associated id.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"keyword\">delete</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>, <span class=\"variable\">value</span> = <span class=\"this\">this</span>.<span class=\"variable\">hashValue</span>(<span class=\"variable\">value</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"this\">this</span>.<span class=\"variable\">idkey</span>, <span class=\"variable\">value</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">id</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span> || <span class=\"variable\">value</span> == <span class=\"keyword\">null</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n        <span class=\"variable\">self</span>.<span class=\"variable\">_delete</span>(<span class=\"variable\">id</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    });\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Deletes an id and its associated unique value.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  id</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">deleteById</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">id</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">id</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">value</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span> || <span class=\"variable\">value</span> == <span class=\"keyword\">null</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n        <span class=\"variable\">self</span>.<span class=\"variable\">_delete</span>(<span class=\"variable\">id</span>, <span class=\"variable\">self</span>.<span class=\"variable\">hashValue</span>(<span class=\"variable\">value</span>), <span class=\"variable\">callback</span>);\n    });\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the number of unique values.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">length</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hlen</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Override this method if you need to hash the unique value\nin the second internal hash (i.e. if values are large).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>return</strong>: <em>string</em>  hashed_value</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">KeyPair</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">hashValue</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">value</span>) {\n    <span class=\"keyword\">return</span> <span class=\"variable\">value</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/Lock.js\"><a href=\"#\">Lock</a></h2></td><td>lib/advanced_structures/Lock.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"variable\">crypto</span> = <span class=\"variable\">require</span>(<span class=\"string\">'crypto'</span>);\n<span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A distributed lock.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Lock</span> = <span class=\"variable\">exports</span>.<span class=\"class\">Lock</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Acquire a temporary lock on some key.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>     key             The unique key of the lock</p></li><li><p><strong>param</strong>: <em>number</em>     ttl             The amount of time (in seconds) before the lock expires</p></li><li><p><strong>param</strong>: <em>Function</em>   callback        Invoked when the process completes</p></li><li><p><strong>param</strong>: <em>Error</em>      callback.err    An error that occurred, if any</p></li><li><p><strong>param</strong>: <em>string</em>     callback.token  The token that was acquired if successful. If the lock was</p><p>                                 not acquired then this will be <code>undefined</code></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Lock</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">acquire</span> = <span class=\"keyword\">function</span>(<span class=\"variable\">key</span>, <span class=\"variable\">ttl</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">client</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>;\n\n    <span class=\"variable\">_createToken</span>(<span class=\"keyword\">function</span>(<span class=\"variable\">err</span>, <span class=\"variable\">token</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n            <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n        }\n\n        <span class=\"variable\">client</span>.<span class=\"variable\">setnx</span>(<span class=\"variable\">key</span>, <span class=\"variable\">token</span>, <span class=\"keyword\">function</span>(<span class=\"variable\">err</span>, <span class=\"variable\">wasSet</span>) {\n            <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n                <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n            } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (!<span class=\"variable\">wasSet</span>) {\n                <span class=\"comment\">// We did not successfully acquire the lock. Since a process can crash after it sets</span>\n                <span class=\"comment\">// the lock but before it sets the expiry, we need to avoid deadlocks by ensuring</span>\n                <span class=\"comment\">// the lock has a TTL associated to it</span>\n                <span class=\"variable\">_ensureTtl</span>(<span class=\"variable\">client</span>, <span class=\"variable\">key</span>, <span class=\"variable\">ttl</span>);\n                <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>();\n            }\n\n            <span class=\"comment\">// Apply the expiry to the lock</span>\n            <span class=\"variable\">client</span>.<span class=\"variable\">expire</span>(<span class=\"variable\">key</span>, <span class=\"variable\">ttl</span>, <span class=\"keyword\">function</span>(<span class=\"variable\">err</span>) {\n                <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n                    <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n                }\n\n                <span class=\"comment\">// Return the token, which is used to release the lock</span>\n                <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">token</span>);\n            });\n        });\n    });\n};</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Release a lock that was acquired with the provided key and token.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>     key                 The key for the lock to release</p></li><li><p><strong>param</strong>: <em>string</em>     token               The token that was generated for the lock acquisition</p></li><li><p><strong>param</strong>: <em>Function</em>   callback            Invoked when the function completes</p></li><li><p><strong>param</strong>: <em>Error</em>      callback.err        An error that occurred, if any</p></li><li><p><strong>param</strong>: <em>boolean</em>    callback.hadLock    Determines whether or not we owned the lock at the time</p><p>                                     that we released it</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Lock</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">release</span> = <span class=\"keyword\">function</span>(<span class=\"variable\">key</span>, <span class=\"variable\">token</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">client</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>;\n\n    <span class=\"variable\">client</span>.<span class=\"variable\">get</span>(<span class=\"variable\">key</span>, <span class=\"keyword\">function</span>(<span class=\"variable\">err</span>, <span class=\"variable\">lockedToken</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n            <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n        } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"variable\">lockedToken</span> !== <span class=\"variable\">token</span>) {\n            <span class=\"comment\">// The current token is not the one we acquired. It's possible we held the lock longer</span>\n            <span class=\"comment\">// than its expiry</span>\n            <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">false</span>);\n        }\n\n        <span class=\"comment\">// We have the token, simply delete the lock key</span>\n        <span class=\"variable\">client</span>.<span class=\"variable\">del</span>(<span class=\"variable\">key</span>, <span class=\"keyword\">function</span>(<span class=\"variable\">err</span>) {\n            <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) {\n                <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n            }\n\n            <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">true</span>);\n        });\n    });\n};</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/Queue.js\"><a href=\"#\">Queue</a></h2></td><td>lib/advanced_structures/Queue.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>),\n    <span class=\"class\">List</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../base_structures/List'</span>).<span class=\"class\">List</span>;</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A simple FIFO/LIFO queue.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createQueue(key [, is_fifo]);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#lists\n   http://en.wikipedia.org/wiki/Queue<em>(data</em>structure)</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = list(values)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Queue</span> = <span class=\"variable\">exports</span>.<span class=\"class\">Queue</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the queue.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  value(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Queue</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">enqueue</span> = <span class=\"class\">Queue</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">list</span>.<span class=\"variable\">unshift</span>(<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove the next element from the queue.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  wait (optional) - block for this many seconds</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Queue</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">dequeue</span> = <span class=\"class\">Queue</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">next</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">list</span>[<span class=\"this\">this</span>.<span class=\"variable\">fifo</span> ? <span class=\"string\">'pop'</span> : <span class=\"string\">'shift'</span>](<span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/RateLimit.js\"><a href=\"#\">RateLimit</a></h2></td><td>lib/advanced_structures/RateLimit.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>See https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da</p>\n\n<p>Count the number of times a subject performs an action over an interval\nin the immediate past - this can be used to rate limit the subject if\nthe count goes over a certain threshold. For example, you could track\nhow many times an IP (the subject) has viewed a page (the action) over\na certain time frame and limit them accordingly.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createRateLimit(action [, options]);</code></p>\n\n<h2>Options</h2>\n\n<p>   <code>bucket_interval</code> - default is 5 seconds\n   <code>bucket_span</code>     - default is 10 minutes\n   <code>subject_expiry</code>  - default is 20 minutes</p>\n\n<h2>Reference</h2>\n\n<p>   https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da\n   http://redis.io/topics/data-types#hash</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)action:&lt;subject1&gt; = hash(bucket =&gt; count)</code>\n   <code>(namespace:)action:&lt;subject2&gt; = hash(bucket =&gt; count)</code>\n   <code>(namespace:)action:&lt;subjectN&gt; = hash(bucket =&gt; count)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">RateLimit</span> = <span class=\"variable\">exports</span>.<span class=\"class\">RateLimit</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Increment the count for the specified subject.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  subject</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">RateLimit</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">subject</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">subject</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">addAll</span>(<span class=\"variable\">subject</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">var</span> <span class=\"variable\">bucket</span> = <span class=\"this\">this</span>.<span class=\"variable\">getBucket</span>(), <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>();\n    <span class=\"variable\">subject</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span> + <span class=\"string\">':'</span> + <span class=\"variable\">subject</span>;\n\n    <span class=\"comment\">//Increment the current bucket</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">hincrby</span>(<span class=\"variable\">subject</span>, <span class=\"variable\">bucket</span>, <span class=\"number integer\">1</span>)\n\n    <span class=\"comment\">//Clear the buckets ahead</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">hdel</span>(<span class=\"variable\">subject</span>, (<span class=\"variable\">bucket</span> + <span class=\"number integer\">1</span>) % <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>)\n         .<span class=\"variable\">hdel</span>(<span class=\"variable\">subject</span>, (<span class=\"variable\">bucket</span> + <span class=\"number integer\">2</span>) % <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>)\n\n    <span class=\"comment\">//Renew the key TTL</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">expire</span>(<span class=\"variable\">subject</span>, <span class=\"this\">this</span>.<span class=\"variable\">subject_expiry</span>);\n\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">err</span>) {\n        <span class=\"keyword\">if</span> (!<span class=\"variable\">callback</span>) <span class=\"keyword\">return</span>;\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>);\n        <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>);\n    });\n\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Count the number of times the subject has performed an action\nin the last <code>interval</code> seconds.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  subject</p></li><li><p><strong>param</strong>: <em>int</em>  interval</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">RateLimit</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">count</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">subject</span>, <span class=\"variable\">interval</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">bucket</span> = <span class=\"this\">this</span>.<span class=\"variable\">getBucket</span>(),\n        <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>(),\n        <span class=\"variable\">count</span> = <span class=\"class\">Math</span>.<span class=\"variable\">floor</span>(<span class=\"variable\">interval</span> / <span class=\"this\">this</span>.<span class=\"variable\">bucket_interval</span>);\n\n    <span class=\"variable\">subject</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span> + <span class=\"string\">':'</span> + <span class=\"variable\">subject</span>;\n\n    <span class=\"comment\">//Get the counts from the previous `count` buckets</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">hget</span>(<span class=\"variable\">subject</span>, <span class=\"variable\">bucket</span>);\n    <span class=\"keyword\">while</span> (<span class=\"variable\">count</span>--) {\n        <span class=\"variable\">multi</span>.<span class=\"variable\">hget</span>(<span class=\"variable\">subject</span>, (--<span class=\"variable\">bucket</span> + <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>) % <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>);\n    }\n\n    <span class=\"comment\">//Add up the counts from each bucket</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">counts</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n        <span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> <span class=\"variable\">count</span> = <span class=\"number integer\">0</span>, <span class=\"variable\">i</span> = <span class=\"number integer\">0</span>, <span class=\"variable\">l</span> = <span class=\"variable\">counts</span>.<span class=\"variable\">length</span>; <span class=\"variable\">i</span> &<span class=\"variable\">lt</span>; <span class=\"variable\">l</span>; <span class=\"variable\">i</span>++) {\n            <span class=\"keyword\">if</span> (<span class=\"variable\">counts</span>[<span class=\"variable\">i</span>]) {\n                <span class=\"variable\">count</span> += <span class=\"variable\">parseInt</span>(<span class=\"variable\">counts</span>[<span class=\"variable\">i</span>], <span class=\"number integer\">10</span>);\n            }\n        }\n        <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">count</span>);\n    });\n\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>An alias for <code>ratelimit.add(subject).count(subject, interval);</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  subject</p></li><li><p><strong>param</strong>: <em>int</em>  interval</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">RateLimit</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">addCount</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">subject</span>, <span class=\"variable\">interval</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">bucket</span> = <span class=\"this\">this</span>.<span class=\"variable\">getBucket</span>(),\n        <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>(),\n        <span class=\"variable\">count</span> = <span class=\"class\">Math</span>.<span class=\"variable\">floor</span>(<span class=\"variable\">interval</span> / <span class=\"this\">this</span>.<span class=\"variable\">bucket_interval</span>);\n\n    <span class=\"variable\">subject</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span> + <span class=\"string\">':'</span> + <span class=\"variable\">subject</span>;\n\n    <span class=\"comment\">//Increment the current bucket</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">hincrby</span>(<span class=\"variable\">subject</span>, <span class=\"variable\">bucket</span>, <span class=\"number integer\">1</span>)\n\n    <span class=\"comment\">//Clear the buckets ahead</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">hdel</span>(<span class=\"variable\">subject</span>, (<span class=\"variable\">bucket</span> + <span class=\"number integer\">1</span>) % <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>)\n         .<span class=\"variable\">hdel</span>(<span class=\"variable\">subject</span>, (<span class=\"variable\">bucket</span> + <span class=\"number integer\">2</span>) % <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>)\n\n    <span class=\"comment\">//Renew the key TTL</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">expire</span>(<span class=\"variable\">subject</span>, <span class=\"this\">this</span>.<span class=\"variable\">subject_expiry</span>);\n\n    <span class=\"comment\">//Get the counts from the previous `count` buckets</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">hget</span>(<span class=\"variable\">subject</span>, <span class=\"variable\">bucket</span>);\n    <span class=\"keyword\">while</span> (<span class=\"variable\">count</span>--) {\n        <span class=\"variable\">multi</span>.<span class=\"variable\">hget</span>(<span class=\"variable\">subject</span>, (--<span class=\"variable\">bucket</span> + <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>) % <span class=\"this\">this</span>.<span class=\"variable\">bucket_count</span>);\n    }\n\n    <span class=\"comment\">//Add up the counts from each bucket</span>\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">counts</span>) {\n        <span class=\"keyword\">if</span> (<span class=\"variable\">err</span>) <span class=\"keyword\">return</span> <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"keyword\">null</span>);\n        <span class=\"keyword\">for</span> (<span class=\"keyword\">var</span> <span class=\"variable\">count</span> = <span class=\"number integer\">0</span>, <span class=\"variable\">i</span> = <span class=\"number integer\">4</span>, <span class=\"variable\">l</span> = <span class=\"variable\">counts</span>.<span class=\"variable\">length</span>; <span class=\"variable\">i</span> &<span class=\"variable\">lt</span>; <span class=\"variable\">l</span>; <span class=\"variable\">i</span>++) {\n            <span class=\"keyword\">if</span> (<span class=\"variable\">counts</span>[<span class=\"variable\">i</span>]) {\n                <span class=\"variable\">count</span> += <span class=\"variable\">parseInt</span>(<span class=\"variable\">counts</span>[<span class=\"variable\">i</span>], <span class=\"number integer\">10</span>);\n            }\n        }\n        <span class=\"variable\">callback</span>(<span class=\"keyword\">null</span>, <span class=\"variable\">count</span>);\n    });\n\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/advanced_structures/SocialGraph.js\"><a href=\"#\">SocialGraph</a></h2></td><td>lib/advanced_structures/SocialGraph.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Build a social graph similar to Twitter's. User ID can be a string or\ninteger, as long as they're unique.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createSocialGraph(id [, prefix]);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#sets</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)(prefix:)id:following = set(ids)</code>\n   <code>(namespace:)(prefix:)id:followers = set(ids)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">SocialGraph</span> = <span class=\"variable\">exports</span>.<span class=\"class\">SocialGraph</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Follow one or more users.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int | SocialGraph | Array</em>  user(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">follow</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">users</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>,\n        <span class=\"variable\">users</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>, <span class=\"string\">'id'</span>),\n        <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>();\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">users</span>[<span class=\"variable\">users</span>.<span class=\"variable\">length</span>-<span class=\"number integer\">1</span>] === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">users</span>.<span class=\"variable\">pop</span>();\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">callback</span> = <span class=\"keyword\">function</span> () {};\n    }\n    <span class=\"variable\">users</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">user</span>) {\n        <span class=\"variable\">multi</span>.<span class=\"variable\">sadd</span>(<span class=\"variable\">self</span>.<span class=\"variable\">key_prefix</span> + <span class=\"variable\">user</span> + <span class=\"string\">':followers'</span>, <span class=\"variable\">self</span>.<span class=\"variable\">id</span>);\n        <span class=\"variable\">multi</span>.<span class=\"variable\">sadd</span>(<span class=\"variable\">self</span>.<span class=\"variable\">following</span>, <span class=\"variable\">user</span>);\n    });\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Unfollow one or more users.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int | SocialGraph | Array</em>  user(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">unfollow</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">users</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">self</span> = <span class=\"this\">this</span>,\n        <span class=\"variable\">users</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>, <span class=\"string\">'id'</span>),\n        <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>();\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">users</span>[<span class=\"variable\">users</span>.<span class=\"variable\">length</span>-<span class=\"number integer\">1</span>] === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">users</span>.<span class=\"variable\">pop</span>();\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">callback</span> = <span class=\"keyword\">function</span> () {};\n    }\n    <span class=\"variable\">users</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">user</span>) {\n        <span class=\"variable\">multi</span>.<span class=\"variable\">srem</span>(<span class=\"variable\">self</span>.<span class=\"variable\">key_prefix</span> + <span class=\"variable\">user</span> + <span class=\"string\">':followers'</span>, <span class=\"variable\">self</span>.<span class=\"variable\">id</span>);\n        <span class=\"variable\">multi</span>.<span class=\"variable\">srem</span>(<span class=\"variable\">self</span>.<span class=\"variable\">following</span>, <span class=\"variable\">user</span>);\n    });\n    <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets the users whom the current users follows as an array.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getFollowing</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">smembers</span>(<span class=\"this\">this</span>.<span class=\"variable\">following</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets an array of users who follow the current user.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getFollowers</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">smembers</span>(<span class=\"this\">this</span>.<span class=\"variable\">followers</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Count how many users the current user follows.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">countFollowing</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">scard</span>(<span class=\"this\">this</span>.<span class=\"variable\">following</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Count how many users follow the current user.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">countFollowers</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">scard</span>(<span class=\"this\">this</span>.<span class=\"variable\">followers</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Checks whether the current user follows the specified user.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | SocialGraph</em>  user</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">isFollowing</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">user</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">user</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">user</span>, <span class=\"string\">'id'</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sismember</span>(<span class=\"this\">this</span>.<span class=\"variable\">following</span>, <span class=\"variable\">user</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Checks whether the specified user follows the current user.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | SocialGraph</em>  user</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">hasFollower</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">user</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">user</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">user</span>, <span class=\"string\">'id'</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sismember</span>(<span class=\"this\">this</span>.<span class=\"variable\">followers</span>, <span class=\"variable\">user</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets an array of common followers for one or more users.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | SocialGraph | Array</em>  user(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getCommonFollowers</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">users</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">users</span> = <span class=\"this\">this</span>.<span class=\"variable\">getSocialKeys</span>(<span class=\"variable\">arguments</span>, <span class=\"string\">'followers'</span>);\n    <span class=\"variable\">users</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">followers</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sinter</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">users</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets an array of users who are followed by all of the specified user(s).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | SocialGraph | Array</em>  user(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getCommonFollowing</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">users</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">users</span> = <span class=\"this\">this</span>.<span class=\"variable\">getSocialKeys</span>(<span class=\"variable\">arguments</span>, <span class=\"string\">'following'</span>);\n    <span class=\"variable\">users</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">following</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sinter</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">users</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets an array of users who follow the current user but do not follow any\nof the other specified users.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | SocialGraph | Array</em>  user(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getDifferentFollowers</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">users</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">users</span> = <span class=\"this\">this</span>.<span class=\"variable\">getSocialKeys</span>(<span class=\"variable\">arguments</span>, <span class=\"string\">'followers'</span>);\n    <span class=\"variable\">users</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">followers</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sdiff</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">users</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets an array of users who are followed by the current user but not any of\nthe other specified users.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | SocialGraph | Array</em>  user(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SocialGraph</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getDifferentFollowing</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">users</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">users</span> = <span class=\"this\">this</span>.<span class=\"variable\">getSocialKeys</span>(<span class=\"variable\">arguments</span>, <span class=\"string\">'following'</span>);\n    <span class=\"variable\">users</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">following</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sdiff</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">users</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/base_structures/Bitfield.js\"><a href=\"#\">Bitfield</a></h2></td><td>lib/base_structures/Bitfield.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Wrap the Redis bit commands.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createBitfield(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/commands#string</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = string</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Bitfield</span> = <span class=\"variable\">exports</span>.<span class=\"class\">Bitfield</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get a single bit</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  bit</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Bitfield</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">get</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">bit</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">getbit</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">bit</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Set a single bit. The callback receives the previous value.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  bit</p></li><li><p><strong>param</strong>: <em>bool</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Bitfield</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">set</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">bit</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">setbit</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">bit</span>, <span class=\"variable\">value</span> ? <span class=\"number integer\">1</span> : <span class=\"number integer\">0</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/base_structures/Hash.js\"><a href=\"#\">Hash</a></h2></td><td>lib/base_structures/Hash.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A wrapper for the Redis hash type.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createHash(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#hashes</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = hash(key =&gt; value)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Hash</span> = <span class=\"variable\">exports</span>.<span class=\"class\">Hash</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get an array of hash keys.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">keys</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hkeys</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get an array of hash values.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">values</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hvals</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the number of hash keys.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">length</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hlen</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Delete a hash key.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  hash_key</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"keyword\">delete</span> = <span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">del</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hdel</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Checks whether a hash key exists.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  hash_key</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">exists</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hexists</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Sets one or more key/value pairs.</p>\n\n<p>To set one key/value pair:\n   <code>hash.set('foo', 'bar', callback);</code></p>\n\n<p>To set multiple:\n   <code>hash.set({key1:'value1', key2:'value2}, callback);</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Object</em>  hash_key</p></li><li><p><strong>param</strong>: <em>string</em>  value (optional)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">set</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">hash_key</span> === <span class=\"string\">'object'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">value</span> || <span class=\"keyword\">function</span> () {};\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hmset</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hset</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Sets a key/value pair if the key doesn't already exist.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  hash_key</p></li><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hsetnx</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Gets one or more key/value pairs.</p>\n\n<p>To get all key/value pairs in the hash:\n   <code>hash.get('foo', callback);</code></p>\n\n<p>To get certain key/value pairs:\n   <code>hash.get(['foo','bar'], callback);</code>\n   <code>hash.get('foo', callback);</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  hash_key (optional)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">get</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">hash_key</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">hash_key</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hgetall</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">hash_key</span>)) {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hmget</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>)\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hget</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Increment the specified hash value.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  hash_key</p></li><li><p><strong>param</strong>: <em>int</em>  amount (optional - default is 1)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">increment</span> =\n<span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">incrBy</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">amount</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">amount</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">amount</span>;\n        <span class=\"variable\">amount</span> = <span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hincrby</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, <span class=\"variable\">amount</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Decrement the specified hash value.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  hash_key</p></li><li><p><strong>param</strong>: <em>int</em>  amount (optional - default is 1)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">decrement</span> =\n<span class=\"class\">Hash</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">decrBy</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">hash_key</span>, <span class=\"variable\">amount</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">amount</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">amount</span>;\n        <span class=\"variable\">amount</span> = <span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">hincrby</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">hash_key</span>, -<span class=\"number integer\">1</span> * <span class=\"variable\">amount</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/base_structures/List.js\"><a href=\"#\">List</a></h2></td><td>lib/base_structures/List.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A wrapper for the Redis list type.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createList(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#lists</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = list(values)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">List</span> = <span class=\"variable\">exports</span>.<span class=\"class\">List</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the list as an array.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">values</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"number integer\">0</span>, -<span class=\"number integer\">1</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get a range of list elements.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>count</em>  end (optional - defaults to the last element)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">range</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">end</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">end</span>;\n        <span class=\"variable\">end</span> = -<span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get one or more elements starting at the specified index.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  index</p></li><li><p><strong>param</strong>: <em>count</em>  count (optional - default is 1)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">get</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">index</span>, <span class=\"variable\">count</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">count</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">count</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lindex</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">index</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">index</span>, <span class=\"variable\">index</span> + <span class=\"variable\">count</span> - <span class=\"number integer\">1</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Cap the length of the list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  length</p></li><li><p><strong>param</strong>: <em>bool</em>  keep_earliest (optional - default is false)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">cap</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">length</span>, <span class=\"variable\">keep_earliest</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">var</span> <span class=\"variable\">start</span> = <span class=\"number integer\">0</span>, <span class=\"variable\">end</span> = -<span class=\"number integer\">1</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">keep_earliest</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"comment\">//Keep the last `length` elements</span>\n        <span class=\"variable\">start</span> = -<span class=\"number integer\">1</span> * <span class=\"variable\">length</span>;\n        <span class=\"variable\">callback</span> = <span class=\"variable\">keep_earliest</span>;\n    } <span class=\"keyword\">else</span> {\n        <span class=\"comment\">//Keep the first `length` elements</span>\n        <span class=\"variable\">end</span> = <span class=\"variable\">length</span> - <span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">ltrim</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove one or more list elements matching the value.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>bool</em>  count (optional - default is 1)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">remove</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">value</span>, <span class=\"variable\">count</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">count</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">count</span>;\n        <span class=\"variable\">count</span> = <span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lrem</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">count</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Trim a list to the specified bounds.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">trim</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">ltrim</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Insert an element before the specified pivot.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  pivot</p></li><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">insertBefore</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">linsert</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"string\">'BEFORE'</span>, <span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Insert an element after the specified pivot.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  pivot</p></li><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">insertAfter</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">linsert</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"string\">'AFTER'</span>, <span class=\"variable\">pivot</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Set the element at the specified index.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  index</p></li><li><p><strong>param</strong>: <em>string</em>  value</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">set</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">index</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lset</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">index</span>, <span class=\"variable\">value</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the number of elements in the list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">length</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">llen</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get and remove the last element in the list. The first param can be used\nto block the process and wait until list elements are available. If the list\nis empty in both examples below, the first example will return <code>null</code>, while\nthe second will wait for up to 3 seconds. If a list element becomes available\nduring the 3 seconds it will be returned, otherwise <code>null</code> will be returned.</p>\n\n<h2>Example</h2>\n\n<p>   <code>list.shift(callback);</code></p>\n\n<h2>Blocking Example</h2>\n\n<p>   <code>list.shift(3, callback)</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  wait (optional) - seconds to block</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">shift</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">wait</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">wait</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lpop</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">blpop</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get and remove the last element in the list. The first param can be used\nto block the process and wait until list elements are available. If the list\nis empty in both examples below, the first example will return <code>null</code>, while\nthe second will wait for up to 3 seconds. If a list element becomes available\nduring the 3 seconds it will be returned, otherwise <code>null</code> will be returned.</p>\n\n<h2>Example</h2>\n\n<p>   <code>list.pop(callback);</code></p>\n\n<h2>Blocking Example</h2>\n\n<p>   <code>list.pop(3, callback)</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  wait (optional) - seconds to block</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">pop</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">wait</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">wait</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">rpop</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">brpop</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the start of the list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | array</em>  value(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">unshift</span> = <span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">lpush</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">values</span>)) {\n        <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>(), <span class=\"variable\">key</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span>;\n        <span class=\"variable\">values</span>.<span class=\"variable\">reverse</span>().<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">value</span>) {\n            <span class=\"variable\">multi</span>.<span class=\"variable\">lpush</span>(<span class=\"variable\">key</span>, <span class=\"variable\">value</span>);\n        });\n        <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">lpush</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">values</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the end of the list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | array</em>  value(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">push</span> = <span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">values</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">values</span>)) {\n        <span class=\"keyword\">var</span> <span class=\"variable\">multi</span> = <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">multi</span>(), <span class=\"variable\">key</span> = <span class=\"this\">this</span>.<span class=\"variable\">key</span>;\n        <span class=\"variable\">values</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">value</span>) {\n            <span class=\"variable\">multi</span>.<span class=\"variable\">rpush</span>(<span class=\"variable\">key</span>, <span class=\"variable\">value</span>);\n        });\n        <span class=\"variable\">multi</span>.<span class=\"variable\">exec</span>(<span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">rpush</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">values</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove the last element of the list and add it to the start\nof another list.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>String | List</em>  list</p></li><li><p><strong>param</strong>: <em>bool</em>  wait (optional) - seconds to block while waiting</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">List</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">popShift</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">list</span>, <span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"variable\">list</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">list</span>);\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">wait</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">wait</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">rpoplpush</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">list</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">brpoplpush</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">list</span>, <span class=\"variable\">wait</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/base_structures/Set.js\"><a href=\"#\">Set</a></h2></td><td>lib/base_structures/Set.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A wrapper for the Redis set type.</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createSet(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#sets</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = set(elements)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Set</span> = <span class=\"variable\">exports</span>.<span class=\"class\">Set</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  element(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">element</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">addAll</span>(<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sadd</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove one or more elements from the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  element(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">remove</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">element</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">removeAll</span>(<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">srem</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get an array of elements in the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">elements</span> = <span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">members</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">smembers</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Move an element to another set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set</em>  dest</p></li><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">move</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">dest</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">smove</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">dest</span>), <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Check whether an element exists in the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">exists</span> = <span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">contains</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sismember</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the length (cardinality) of the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">length</span> = <span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">cardinality</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">scard</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get a random element from the set and optionally remove it.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>bool</em>  remove (optional - default is false)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">random</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">remove</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">remove</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">remove</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">srandmember</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">spop</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the intersection of one or more sets.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">inter</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">sets</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">sets</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>);\n    <span class=\"variable\">sets</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sinter</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">sets</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the intersection of one or more sets and store it another\nset (dest).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set</em>  dest</p></li><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">interStore</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">dest</span>, <span class=\"variable\">sets</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">sets</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>);\n    <span class=\"variable\">dest</span> = <span class=\"variable\">sets</span>.<span class=\"variable\">shift</span>();\n    <span class=\"variable\">sets</span>.<span class=\"variable\">unshift</span>(<span class=\"variable\">dest</span>, <span class=\"this\">this</span>.<span class=\"variable\">key</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sinterstore</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">sets</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the union of one or more sets.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">union</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">sets</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">sets</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>);\n    <span class=\"variable\">sets</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sunion</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">sets</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the union of one or more sets and store it another\nset (dest).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set</em>  dest</p></li><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">unionStore</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">dest</span>, <span class=\"variable\">sets</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">sets</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>);\n    <span class=\"variable\">dest</span> = <span class=\"variable\">sets</span>.<span class=\"variable\">shift</span>();\n    <span class=\"variable\">sets</span>.<span class=\"variable\">unshift</span>(<span class=\"variable\">dest</span>, <span class=\"this\">this</span>.<span class=\"variable\">key</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sunionstore</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">sets</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the difference of one or more sets.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">diff</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">sets</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">sets</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>);\n    <span class=\"variable\">sets</span>.<span class=\"variable\">unshift</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sdiff</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">sets</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the difference of one or more sets and store it another\nset (dest).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Set</em>  dest</p></li><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">Set</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">diffStore</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">dest</span>, <span class=\"variable\">sets</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">sets</span> = <span class=\"this\">this</span>.<span class=\"variable\">getKeys</span>(<span class=\"variable\">arguments</span>);\n    <span class=\"variable\">dest</span> = <span class=\"variable\">sets</span>.<span class=\"variable\">shift</span>();\n    <span class=\"variable\">sets</span>.<span class=\"variable\">unshift</span>(<span class=\"variable\">dest</span>, <span class=\"this\">this</span>.<span class=\"variable\">key</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">sdiffstore</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">sets</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr><tr class=\"filename\"><td><h2 id=\"lib/base_structures/SortedSet.js\"><a href=\"#\">SortedSet</a></h2></td><td>lib/base_structures/SortedSet.js</td></tr><tr class=\"code\">\n<td class=\"docs\">\n<p>Module dependencies.\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">Structure</span> = <span class=\"variable\">require</span>(<span class=\"string\">'../Structure'</span>);</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>A wrapper for the Redis sorted set (zset) type. Each element has a\nscore which is used to rank and order all elements in the set. Elements\nare ranked from lowest score to highest (the lowest score has\na rank of 0)</p>\n\n<h2>Usage</h2>\n\n<p>   <code>redback.createSortedSet(key);</code></p>\n\n<h2>Reference</h2>\n\n<p>   http://redis.io/topics/data-types#sorted-sets</p>\n\n<h2>Redis Structure</h2>\n\n<p>   <code>(namespace:)key = zset(score =&gt; element)</code>\n </p>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"keyword\">var</span> <span class=\"class\">SortedSet</span> = <span class=\"variable\">exports</span>.<span class=\"class\">SortedSet</span> = <span class=\"class\">Structure</span>.<span class=\"keyword\">new</span>();</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Add one or more elements to the set.</p>\n\n<p>To add a single element and score:\n   <code>set.add(12, 'foo', callback);</code></p>\n\n<p>To add multiple elements/scores:\n   <code>set.add({foo:12, bar:3}, callback);</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  score (optional)</p></li><li><p><strong>param</strong>: <em>string | Object</em>  element(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">add</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">score</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">score</span> === <span class=\"string\">'object'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">element</span>;\n        <span class=\"variable\">element</span> = <span class=\"variable\">score</span>;\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">addAll</span>(<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zadd</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">score</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove one or more elements from the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string | Array</em>  element(s)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">remove</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">element</span>)) {\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>.<span class=\"variable\">removeAll</span>(<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrem</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the number of elements in the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">length</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zcard</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Check whether an element exists in the set.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">exists</span> =\n<span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">contains</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"keyword\">function</span> (<span class=\"variable\">err</span>, <span class=\"variable\">score</span>) {\n        <span class=\"variable\">callback</span>(<span class=\"variable\">err</span>, <span class=\"variable\">score</span> != <span class=\"keyword\">null</span>);\n    });\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the rank of the specified element.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">rank</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrank</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>)\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the score of the specified element.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">score</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>)\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Increment the specified element's score.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>int</em>  amount (optional - default is 1)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em>\n;</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">increment</span> =\n<span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">incrBy</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">amount</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">amount</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">amount</span>;\n        <span class=\"variable\">amount</span> = <span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zincrby</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">amount</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Decrement the specified element's score.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>string</em>  element</p></li><li><p><strong>param</strong>: <em>int</em>  amount (optional - default is 1)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em>\n;</p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">decrement</span> =\n<span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">decrBy</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">element</span>, <span class=\"variable\">amount</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">amount</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">amount</span>;\n        <span class=\"variable\">amount</span> = <span class=\"number integer\">1</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zincrby</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, -<span class=\"number integer\">1</span> * <span class=\"variable\">amount</span>, <span class=\"variable\">element</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get all elements in the set as an object <code>{element: score, ...}</code>.\nIf <code>without_scores</code> is true then just an array of elements is returned.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>bool</em>  without_scores (optional - scores are included by default)</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">get</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">without_scores</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">without_scores</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">without_scores</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"number integer\">0</span>, -<span class=\"number integer\">1</span>, <span class=\"string\">'WITHSCORES'</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n    } <span class=\"keyword\">else</span> {\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"number integer\">0</span>, -<span class=\"number integer\">1</span>, <span class=\"variable\">callback</span>);\n    }\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get elements with scores between the specified range. Elements are returned\nas an object <code>{element: score, ..}</code> and ordered from highest score to lowest.</p>\n\n<p>Note that the <code>start</code> and <code>end</code> range is inclusive and can be an integer or\nthe constants <code>redback.INF</code> to represent infinity, or <code>redback.NINF</code> to\nrepresent negative infinity. <code>start</code> must be &lt;= <code>end</code>.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>int</em>  count (optional) - the maximum number of elements to return</p></li><li><p><strong>param</strong>: <em>int</em>  offset (optional) - if using count, start at this offset</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getScores</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">count</span>, <span class=\"variable\">offset</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = <span class=\"string\">'-inf'</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = <span class=\"string\">'+inf'</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">count</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">count</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrangebyscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>,\n            <span class=\"string\">'WITHSCORES'</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n    } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">offset</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">offset</span>;\n        <span class=\"variable\">offset</span> = <span class=\"number integer\">0</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrangebyscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"string\">'WITHSCORES'</span>,\n        <span class=\"string\">'LIMIT'</span>, <span class=\"variable\">offset</span>, <span class=\"variable\">count</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>The same as <code>getScores()</code> but elements are ordered from lowest score to\nhighest.</p>\n\n<p>Note that <code>end</code> must be &lt;= <code>start</code>.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>int</em>  count (optional) - the maximum number of elements to return</p></li><li><p><strong>param</strong>: <em>int</em>  offset (optional) - if using count, start at this offset</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getScoresReverse</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">count</span>, <span class=\"variable\">offset</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = <span class=\"string\">'+inf'</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = <span class=\"string\">'-inf'</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">count</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">count</span>;\n        <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrevrangebyscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>,\n            <span class=\"string\">'WITHSCORES'</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n        <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n    } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">offset</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">offset</span>;\n        <span class=\"variable\">offset</span> = <span class=\"number integer\">0</span>;\n    }\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrevrangebyscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"string\">'WITHSCORES'</span>,\n        <span class=\"string\">'LIMIT'</span>, <span class=\"variable\">offset</span>, <span class=\"variable\">count</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove elements with scores between the specified range (inclusive).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">removeScores</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = <span class=\"string\">'-inf'</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = <span class=\"string\">'+inf'</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zremrangebyscore</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Count the number of elements with scores between the specified\nrange (inclusive).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">countScores</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = <span class=\"string\">'-inf'</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = <span class=\"string\">'+inf'</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zcount</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get elements with ranks between the specified range (inclusive).</p>\n\n<p>To get the first 3 elements in the set (with the highest scores):\n   <code>set.getRanks(0, 2, callback);</code></p>\n\n<p>To get the last 3 elements in the set (lowest scores):\n   <code>set.getRanks(-3, -1, callback);</code></p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getRanks</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = <span class=\"number integer\">0</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = -<span class=\"number integer\">1</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>,\n        <span class=\"string\">'WITHSCORES'</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>The same as <code>getRanks()</code> but elements are ordered from lowest score\nto the highest.</p>\n\n<p>Note that start and end have been deliberately switched for consistency.</p>\n\n<p>getScoresReverse(arg1, arg2, ..) expects arg1 &gt;= arg2 and so does this\nmethod.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">getRanksReverse</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">end</span>, <span class=\"variable\">start</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = -<span class=\"number integer\">1</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = <span class=\"number integer\">0</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zrevrange</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>,\n        <span class=\"string\">'WITHSCORES'</span>, <span class=\"this\">this</span>.<span class=\"variable\">parseScores</span>(<span class=\"variable\">callback</span>));\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Remove elements with ranks between the specified range (inclusive).</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  start</p></li><li><p><strong>param</strong>: <em>int</em>  end</p></li><li><p><strong>param</strong>: <em>Function</em>  callback (optional)</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">removeRanks</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"variable\">callback</span> = <span class=\"variable\">callback</span> || <span class=\"keyword\">function</span> () {};\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">start</span>) <span class=\"variable\">start</span> = -<span class=\"number integer\">1</span>;\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">null</span> === <span class=\"variable\">end</span>) <span class=\"variable\">end</span> = <span class=\"number integer\">0</span>;\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zremrangebyrank</span>(<span class=\"this\">this</span>.<span class=\"variable\">key</span>, <span class=\"variable\">start</span>, <span class=\"variable\">end</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get <code>count</code> elements with the highest scores.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  count</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">highestScores</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">count</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">getRanks</span>(-<span class=\"number integer\">1</span> * <span class=\"variable\">count</span>, -<span class=\"number integer\">1</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get <code>count</code> elements with the lowest scores.</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  count</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">lowestScores</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">count</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"this\">this</span>.<span class=\"variable\">getRanks</span>(<span class=\"number integer\">0</span>, <span class=\"variable\">count</span> - <span class=\"number integer\">1</span>, <span class=\"variable\">callback</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the intersection of one or more sets. For more information on weights,\naggregate functions, etc. see: http://redis.io/commands/zinterstore</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  dest</p></li><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>int | Array</em>  weights (optional)</p></li><li><p><strong>param</strong>: <em>string</em>  aggregate (optional) - either SUM, MIN or MAX</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">inter</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">dest</span>, <span class=\"variable\">sets</span>, <span class=\"variable\">weights</span>, <span class=\"variable\">aggregate</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">args</span> = [], <span class=\"variable\">self</span> = <span class=\"this\">this</span>;\n    <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">dest</span>));\n\n    <span class=\"comment\">//weights/aggregate are optional</span>\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">weights</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">weights</span>;\n        <span class=\"variable\">weights</span> = <span class=\"variable\">aggregate</span> = <span class=\"variable\">false</span>;\n    } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">aggregate</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">aggregate</span>;\n        <span class=\"variable\">aggregate</span> = <span class=\"variable\">false</span>;\n    }\n\n    <span class=\"comment\">//ZINTERSTORE destination numkeys key [key ...]</span>\n    <span class=\"comment\">//    [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]</span>\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">sets</span>)) {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">sets</span>.<span class=\"variable\">length</span>);\n        <span class=\"variable\">sets</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">set</span>) {\n            <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">self</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">set</span>));\n        });\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"number integer\">1</span>, <span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">sets</span>));\n    }\n    <span class=\"keyword\">if</span> (<span class=\"variable\">weights</span>) {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"string\">'WEIGHTS'</span>);\n        <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">weights</span>)) {\n            <span class=\"variable\">weights</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">weight</span>) {\n                <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">weight</span>);\n            });\n        } <span class=\"keyword\">else</span> {\n            <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">weights</span>);\n        }\n    }\n    <span class=\"keyword\">if</span> (<span class=\"variable\">aggregate</span>) {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"string\">'AGGREGATE'</span>, <span class=\"variable\">aggregate</span>);\n    }\n    <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">callback</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zinterstore</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">args</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}</code></pre>\n</td>\n</tr>\n<tr class=\"code\">\n<td class=\"docs\">\n<p>Get the union of one or more sets. For more information on weights,\naggregate functions, etc. see: http://redis.io/commands/zunionstore</p>\n\n<h2></h2>\n\n<ul><li><p><strong>param</strong>: <em>int</em>  dest</p></li><li><p><strong>param</strong>: <em>string | Set | Array</em>  set(s)</p></li><li><p><strong>param</strong>: <em>int | Array</em>  weights (optional)</p></li><li><p><strong>param</strong>: <em>string</em>  aggregate (optional) - either SUM, MIN or MAX</p></li><li><p><strong>param</strong>: <em>Function</em>  callback</p></li><li><p><strong>return</strong>: <em>this</em></p></li><li><p><strong>api</strong>: <em>public</em></p></li></ul>\n</td>\n<td class=\"code\">\n<pre><code><span class=\"class\">SortedSet</span>.<span class=\"variable\">prototype</span>.<span class=\"variable\">union</span> = <span class=\"keyword\">function</span> (<span class=\"variable\">dest</span>, <span class=\"variable\">sets</span>, <span class=\"variable\">weights</span>, <span class=\"variable\">aggregate</span>, <span class=\"variable\">callback</span>) {\n    <span class=\"keyword\">var</span> <span class=\"variable\">args</span> = [], <span class=\"variable\">self</span> = <span class=\"this\">this</span>;\n    <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">dest</span>));\n\n    <span class=\"comment\">//weights/aggregate are optional</span>\n    <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">weights</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">weights</span>;\n        <span class=\"variable\">weights</span> = <span class=\"variable\">aggregate</span> = <span class=\"variable\">false</span>;\n    } <span class=\"keyword\">else</span> <span class=\"keyword\">if</span> (<span class=\"keyword\">typeof</span> <span class=\"variable\">aggregate</span> === <span class=\"string\">'function'</span>) {\n        <span class=\"variable\">callback</span> = <span class=\"variable\">aggregate</span>;\n        <span class=\"variable\">aggregate</span> = <span class=\"variable\">false</span>;\n    }\n\n    <span class=\"comment\">//ZUNIONSTORE destination numkeys key [key ...]</span>\n    <span class=\"comment\">//    [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]</span>\n    <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">sets</span>)) {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">sets</span>.<span class=\"variable\">length</span>);\n        <span class=\"variable\">sets</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">set</span>) {\n            <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">self</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">set</span>));\n        });\n    } <span class=\"keyword\">else</span> {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"number integer\">1</span>, <span class=\"this\">this</span>.<span class=\"variable\">getKey</span>(<span class=\"variable\">sets</span>));\n    }\n    <span class=\"keyword\">if</span> (<span class=\"variable\">weights</span>) {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"string\">'WEIGHTS'</span>);\n        <span class=\"keyword\">if</span> (<span class=\"class\">Array</span>.<span class=\"variable\">isArray</span>(<span class=\"variable\">weights</span>)) {\n            <span class=\"variable\">weights</span>.<span class=\"variable\">forEach</span>(<span class=\"keyword\">function</span> (<span class=\"variable\">weight</span>) {\n                <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">weight</span>);\n            });\n        } <span class=\"keyword\">else</span> {\n            <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">weights</span>);\n        }\n    }\n    <span class=\"keyword\">if</span> (<span class=\"variable\">aggregate</span>) {\n        <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"string\">'AGGREGATE'</span>, <span class=\"variable\">aggregate</span>);\n    }\n    <span class=\"variable\">args</span>.<span class=\"variable\">push</span>(<span class=\"variable\">callback</span>);\n    <span class=\"this\">this</span>.<span class=\"variable\">client</span>.<span class=\"variable\">zunionstore</span>.<span class=\"variable\">apply</span>(<span class=\"this\">this</span>.<span class=\"variable\">client</span>, <span class=\"variable\">args</span>);\n    <span class=\"keyword\">return</span> <span class=\"this\">this</span>;\n}\n</code></pre>\n</td>\n</tr>\t</body>\n</html></tbody></table>"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n\n    <title>Redback - Redis-backed persistence for Node.JS</title>\n\n    <link rel=\"icon\" type=\"image/png\" href=\"favicon.png\" />\n    <link href='http://fonts.googleapis.com/css?family=Gruppo' rel='stylesheet' type='text/css' />\n    <script src=\"http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js\"></script>\n    <script type=\"text/javascript\">\n\n    /*\n    Credits\n      jQuery noise: https://github.com/DanielRapp/Noisy\n      Sexy buttons: https://github.com/ubuwaits/css3-buttons\n      Title font:   http://www.google.com/webfonts/family?family=Gruppo\n      Favicon:      http://prothemedesign.com/circular-icons\n    */\n\n    (function(a){a.fn.noisy=function(b){return this.each(function(){var c=document.createElement(\"canvas\"),h=c.getContext(\"2d\");if(!h&&b.fallback!==undefined&&b.fallback!==\"\")a(this).css(\"background-image\",\"url(\"+b.fallback+\"),\"+a(this).css(\"background-image\"));else{b=a.extend({},a.fn.noisy.defaults,b);c.width=c.height=b.size;for(var d=h.createImageData(c.width,c.height),e=function(i,k){return Math.floor(Math.random()*(k-i)+i)},j=0;j<b.intensity*Math.pow(b.size,2);j++){var f=e(0,c.width),g=e(0,c.height);f=(f+g*d.width)*4;g=e(0,255);d.data[f]=g;d.data[f+1]=b.monochrome?g:e(0,255);d.data[f+2]=b.monochrome?g:e(0,255);d.data[f+3]=e(0,255*b.opacity)}h.putImageData(d,0,0);a(this).data(\"original-css\")==undefined&&a(this).data(\"original-css\",a(this).css(\"background-image\"));a(this).css(\"background-image\",\"url(\"+c.toDataURL(\"image/png\")+\"),\"+a(this).data(\"original-css\"))}})};a.fn.noisy.defaults={intensity:0.9,size:200,opacity:0.08,fallback:\"\",monochrome:false}})(jQuery);\n\n    $(function () {\n        $('body').noisy({\n            'intensity' : 1,\n            'size' : 200,\n            'opacity' : 0.070,\n            'fallback' : '',\n            'monochrome' : false\n        }).css('background-color', '#FCFCFC');\n    });\n\n    </script>\n\n    <style type=\"text/css\">\n\n        body {\n            background-color: #FCFCFC;\n            font-family: Droid Sans,Arial,Sans Serif;\n            font-size: 16px;\n            margin: 0;\n            border-top: 3px solid #E60B0B;\n            color: #444;\n        }\n        #fork {\n            top: 0;\n            right: 0;\n            position: fixed;\n            z-index: 999;\n            opacity: 0.8;\n        }\n        #tag {\n            float: right;\n            margin-top: 54px;\n        }\n        #fork:hover {\n            opacity: 0.7;\n        }\n        #container {\n            width: 700px;\n            margin: 0 auto;\n        }\n        #header {\n            height: 70px;\n            border-bottom: 2px dotted #bbb;\n            margin-bottom: 10px;\n        }\n        #header h1 {\n            font-family: 'Gruppo',Arial, Sans Serif;\n            font-size: 60px;\n            font-weight: bold;\n            letter-spacing: -1px;\n            text-shadow: 1px 2px 2px rgba(30,30,30,0.6);\n        }\n        #header h1 .red {\n            color: #E60B0B;\n            text-shadow: 1px 2px 2px rgba(80,0,0,0.6);\n        }\n        #content h2 {\n            font-size: 24px;\n            margin: 28px 0 14px 0;\n            text-shadow: 1px 1px 1px rgba(20,20,20,0.2);\n        }\n        #content p {\n            padding-left: 2px;\n            line-height: 1.6em;\n        }\n        a, a:visited {\n            text-decoration: none;\n            color: #E60B0B;\n        }\n        a:hover {\n            text-decoration: underline;\n            opacity: 0.8;\n        }\n        code {\n            display: block;\n            padding: 10px;\n            border: 2px solid #ccc;\n            background-color: rgba(80, 80, 80, .09);\n            margin-bottom: 2px;\n        }\n        button {\n          background: #c63929;\n          background: -moz-linear-gradient(top, #ee432e 0%, #c63929 50%, #b51700 50%, #891100 100%);\n          background: -webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #ee432e), color-stop(0.5, #c63929), color-stop(0.5, #b51700), color-stop(1, #891100));\n          border: 1px solid #951100;\n          -moz-border-radius: 5px;\n          -webkit-border-radius: 5px;\n          border-radius: 5px;\n          -moz-box-shadow: inset 0px 0px 0px 1px rgba(255, 115, 100, 0.4), 0 1px 3px #333;\n          -webkit-box-shadow: inset 0px 0px 0px 1px rgba(255, 115, 100, 0.4), 0 1px 3px #333;\n          box-shadow: inset 0px 0px 0px 1px rgba(255, 115, 100, 0.4), 0 1px 3px #333;\n          color: #fff;\n          font-family: \"helvetica neue\", helvetica, arial, sans-serif;\n          font-size: 20px;\n          font-weight: bold;\n          line-height: 1;\n          padding: 12px 0 14px 0;\n          text-align: center;\n          text-shadow: 0px -1px 1px rgba(0, 0, 0, .8);\n          width: 338px;\n          margin-top: 7px;\n        }\n        button:hover {\n          background: #cb0500;\n          background: -moz-linear-gradient(top, #f37873 0%, #db504d 50%, #cb0500 50%, #a20601 100%);\n          background: -webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #f37873), color-stop(0.5, #db504d), color-stop(0.5, #cb0500), color-stop(1, #a20601));\n          cursor: pointer;\n        }\n        button:active {\n          background: #b30300;\n          background: -moz-linear-gradient(top, #d43c28 0%, #ad3224 50%, #9c1500 50%, #700d00 100%);\n          background: -webkit-gradient(linear, 0 0, 0 100%, color-stop(0, #d43c28), color-stop(0.5, #ad3224), color-stop(0.5, #9c1500), color-stop(1, #700d00));\n          -moz-box-shadow: inset 0px 0px 0px 1px rgba(255, 115, 100, 0.4);\n          -webkit-box-shadow: inset 0px 0px 0px 1px rgba(255, 115, 100, 0.4);\n          box-shadow: inset 0px 0px 0px 1px rgba(255, 115, 100, 0.4);\n        }\n        button.first {\n            margin-right: 20px;\n        }\n        ul {\n            list-style-type: square;\n            line-height: 1.5em;\n        }\n        #copyright {\n            padding-top: 20px;\n            font-size: 12px;\n        }\n        a.hint {\n            font-size: 11px;\n            font-style: italic;\n            margin-top: 2px;\n            color: #888;\n            float: right;\n        }\n\n    </style>\n\n    <script type=\"text/javascript\">\n      var _gaq = _gaq || [];\n      _gaq.push(['_setAccount', 'UA-286321-6']);\n      _gaq.push(['_trackPageview']);\n      (function() {\n        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;\n        ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';\n        var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);\n      })();\n    </script>\n\n</head>\n<body>\n\n    <a id=\"fork\" href=\"https://github.com/chriso/redback\">\n        <img alt=\"Fork me on GitHub\" src=\"fork.png\" />\n    </a>\n\n    <div id=\"container\">\n        <div id=\"header\">\n            <h1><span class=\"red\">Red</span>back</h1>\n        </div>\n\n        <div id=\"content\">\n            <h2>What is it?</h2>\n                <p>A fast, high-level <a class=\"redis\" href=\"http://redis.io\">Redis</a> library for <a class=\"nodejs\" href=\"http://nodejs.org\">Node.JS</a> that exposes an accessible and extensible interface to the Redis <a href=\"http://redis.io/topics/data-types\">data types</a>.\n                </p>\n                <p>\n                    Redback comes bundled with advanced Redis structures such as the\n                        <a href=\"https://github.com/chriso/redback\">Social Graph</a> or\n                        <a href=\"https://github.com/chriso/redback\">Rate Limiter</a>.\n                        You can also build your own Redis-backed structures with ease.\n                </p>\n\n            <h2>How do I get it?</h2>\n                <code>npm install redback</code>\n\n            <h2>Learn more</h2>\n                <p>See the <a href=\"https://github.com/chriso/redback\">GitHub repository</a> for more information. For an API, see the <a href=\"http://redbackjs.com/api.html\">annotated source</a>.</p>\n\n            <button class=\"first\" onclick=\"location.href='https://github.com/chriso/redback';\">Source</button>\n            <button onclick=\"location.href='api.html';\">Documentation</button>\n\n        </div>\n\n        <div id=\"copyright\">\n            &copy; Chris O'Hara (<a href=\"http://github.com/chriso/redback/raw/master/LICENSE\">MIT License</a>)\n        </div>\n\n    </div>\n\n</body>\n</html>\n"
  },
  {
    "path": "index.js",
    "content": "module.exports = require('./lib/Redback');\n"
  },
  {
    "path": "lib/Cache.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Use Redis as a cache backend.\n *\n * Usage:\n *    `redback.createCache(namespace);`\n *\n * Reference:\n *    http://redis.io/commands#string\n *\n * Redis Structure:\n *    `(namespace:)cache_namespace:key = string`\n */\n\nvar Cache = exports.Cache = function (client, namespace) {\n    this.client = client;\n    this.namespace = namespace;\n}\n\n/**\n * Add the namespace on to cache keys.\n *\n * @param {string} key\n * @return namespaced_key;\n * @api private\n */\n\nCache.prototype.getKey = function (key) {\n    return this.namespace + ':' + key;\n}\n\n/**\n * Cache one or more values.\n *\n * To cache a single value by key:\n *    `cache.set('foo', 'bar', callback);`\n *\n * To set multiple cached values by key:\n *    `cache.set({foo:'bar', key2:'value2'}, callback);`\n *\n * @param {string} key\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.set = function (key, value, expiry, callback) {\n    callback = callback || function () {};\n    if (typeof expiry === 'function') {\n        callback = expiry;\n        this.client.set(this.getKey(key), value, callback);\n    } else if (typeof value === 'function') {\n        callback = value;\n        var i, set = [];\n        for (i in key) {\n            set.push(this.getKey(i));\n            set.push(key[i]);\n        }\n        set.push(callback);\n        this.client.mset.apply(this.client, set);\n    } else {\n        this.client.setex(this.getKey(key), expiry, value, callback);\n    }\n    return this;\n}\n\n/**\n * Add one or more values to the cache, but only if the cache\n * key(s) do not already exist.\n *\n * @param {string|Object} key\n * @param {string} value (optional)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.add = function (key, value, callback) {\n    callback = callback || function () {};\n    if (typeof value === 'function') {\n        callback = value;\n        var i, set = [];\n        for (i in key) {\n            set.push(this.getKey(i));\n            set.push(key[i]);\n        }\n        set.push(callback);\n        this.client.msetnx.apply(this.client, set);\n    } else {\n        this.client.setnx(this.getKey(key), value, callback);\n    }\n    return this;\n}\n\n/**\n * Get one or more values from the cache.\n *\n * To get a single cached value by key:\n *    `cache.get('foo', callback);`\n *\n * To get multiple cached values by key:\n *    `cache.get(['foo','bar'], callback);`\n *\n * To get all cached values:\n *    `cache.get(callback);`\n *\n * @param {string} key\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nCache.prototype.get = function (key, callback) {\n    var namespace_len = this.namespace.length + 1,\n        self = this;\n\n    var multi_get = function (keys) {\n        var get_args = [];\n        keys.forEach(function (key) {\n            get_args.push(key);\n        })\n        get_args.push(function (err, values) {\n            if (err) return callback(err, null);\n            var i, l, ret = {};\n            for (i = 0, l = keys.length; i < l; i++) {\n                ret[keys[i].substr(namespace_len)] = values[i];\n            }\n            callback(null, ret);\n        });\n        self.client.mget.apply(self.client, get_args);\n    }\n\n    if (typeof key === 'function') {\n        callback = key;\n        this.keys('*', true, function (err, keys) {\n            if (err) return callback(err, null);\n            multi_get(keys);\n        });\n    } else if (Array.isArray(key)) {\n        if (!key.length) return callback(null, null);\n        for (var get = [], i = 0, l = key.length; i < l; i++) {\n            key[i] = this.getKey(key[i]);\n        }\n        multi_get(key);\n    } else {\n        this.client.get(this.getKey(key), callback);\n    }\n    return this;\n}\n\n/**\n * Set a cache key and return the current value.\n *\n * @param {string} key\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nCache.prototype.getSet = function (key, value, callback) {\n    this.client.getset(this.getKey(key), value, callback);\n    return this;\n}\n\n/**\n * Check whether a cache key exists.\n *\n * @param {string} key\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nCache.prototype.exists = function (key, callback) {\n    this.client.exists(this.getKey(key), callback);\n    return this;\n}\n\n/**\n * Increment the specified cache value.\n *\n * @param {string} key\n * @param {int} amount (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.increment =\nCache.prototype.incrBy = function (key, amount, callback) {\n    callback = callback || function () {};\n    if (typeof amount === 'function') {\n        callback = amount;\n        amount = 1;\n    }\n    this.client.incrby(this.getKey(key), amount, callback);\n    return this;\n}\n\n/**\n * Decrement the specified cache value.\n *\n * @param {string} key\n * @param {int} amount (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.decrement =\nCache.prototype.decrBy = function (key, amount, callback) {\n    callback = callback || function () {};\n    if (typeof amount === 'function') {\n        callback = amount;\n        amount = 1;\n    }\n    this.client.decrby(this.getKey(key), amount, callback);\n    return this;\n}\n\n/**\n * Get all cache keys matching the pattern.\n *\n * @param {string} pattern (optional - default is *)\n * @param {bool} keep_namespace (optional - default is false)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nCache.prototype.keys = function (pattern, keep_namespace, callback) {\n    if (typeof pattern === 'function') {\n        keep_namespace = false;\n        callback = pattern;\n        pattern = '*';\n    } else if (typeof keep_namespace === 'function') {\n        callback = keep_namespace;\n        keep_namespace = false;\n    }\n    var self = this;\n    if (keep_namespace) {\n        this.client.keys(this.namespace + ':' + pattern, function (err, keys) {\n            if (err) return callback(err, null);\n            if (!keys) return callback(null, []);\n            callback(null, keys);\n        });\n    } else {\n        var namespace_len = this.namespace.length + 1;\n        this.client.keys(this.namespace + ':' + pattern, function (err, keys) {\n            if (err) return callback(err, null);\n            if (!keys) return callback(null, []);\n            if (null == keys) return callback(null, []);\n            for (var i = 0, l = keys.length; i < l; i++) {\n                keys[i] = keys[i].substr(namespace_len);\n            }\n            callback(null, keys);\n        });\n    }\n}\n\n/**\n * Flush all cache keys matching the pattern.\n *\n * @param {string} pattern (optional - default is *)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.flush = function (pattern, callback) {\n    callback = callback || function () {};\n    if (typeof pattern === 'function') {\n        callback = pattern;\n        pattern = '*';\n    }\n    var self = this;\n    this.keys(pattern, true, function (err, keys) {\n        if (err) return callback(err, null);\n        if (!keys || keys.length === 0) return callback(err, []);\n        var error = false, remaining = keys.length, del_count = 0;\n        keys.forEach(function (key) {\n            self.client.del(key, function (err, deleted) {\n                if (error) {\n                    return;\n                } else if (err) {\n                    error = true;\n                    return callback(err, null);\n                }\n                del_count++;\n                if (!--remaining) callback(err, del_count);\n            });\n        });\n    });\n}\n\n\n/**\n * Expire the cache key after a certain number of seconds.\n *\n * @param {int} ttl\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.expire = function (key, ttl, callback) {\n    callback = callback || function () {};\n    this.client.expire(this.getKey(key), ttl, callback);\n    return this;\n}\n\n/**\n * Expire the cache key at a certain date.\n *\n * @param {string} key\n * @param {Date} when\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.expireAt = function (key, when, callback) {\n    callback = callback || function () {};\n    if (typeof when.getTime === 'function') {\n        when = Math.round(when.getTime() / 1000); //ms => s\n    }\n    this.client.expireat(this.getKey(key), when, callback);\n    return this;\n}\n\n/**\n * Get the number of seconds before the cache key expires.\n *\n * @param {string} key\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.ttl = function (key, callback) {\n    callback = callback || function () {};\n    this.client.ttl(this.getKey(key), callback);\n    return this;\n}\n\n/**\n * Checks whether a cache key has an expiry.\n *\n * @param {string} key\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nCache.prototype.isVolatile = function (key, callback) {\n    this.client.ttl(this.getKey(key), function (err, ttl) {\n        if (err) return callback(err, null);\n        callback(null, ttl != -1);\n    });\n    return this;\n}\n\n/**\n * Remove the cache key's associated expiry.\n *\n * @param {string} key\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCache.prototype.persist = function (key, callback) {\n    callback = callback || function () {};\n    this.client.persist(this.getKey(key), callback);\n    return this;\n}\n"
  },
  {
    "path": "lib/Channel.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar EventEmitter = require('events').EventEmitter;\n\n/**\n * Wrap the Redis pub/sub commands.\n *\n * Usage:\n *    `redback.createChannel(name);`\n *\n * Reference:\n *    http://redis.io/topics/pubsub\n */\n\nvar Channel = exports.Channel = function (client, channel_name) {\n    this.name = channel_name;\n    this.setClient(client);\n}\n\n/**\n * Channel is an event emitter.\n */\n\nChannel.prototype = new EventEmitter();\n\n/**\n * Bind a new Redis client (e.g. if not exclusively using pub/sub mode).\n *\n * @param {Object} client\n * @return this\n * @api public\n */\n\nChannel.prototype.setClient = function (client) {\n    this.client = client;\n    var self = this;\n    ['message','subscribe','unsubscribe'].forEach(function (event) {\n        self.client.on(event, function (channel, arg) {\n            if (channel == self.name) {\n                self.emit(event, arg);\n            }\n        });\n    });\n    return this;\n}\n\n/**\n * Publish a message to the channel.\n *\n * @param {string} msg\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nChannel.prototype.publish = function (msg, callback) {\n    this.client.publish(this.name, msg, callback);\n    return this;\n}\n\n/**\n * Subscribe to the channel.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nChannel.prototype.subscribe = function (callback) {\n    this.client.subscribe(this.name);\n    if (typeof callback === 'function') {\n        this.on('subscribe', callback);\n    }\n    return this;\n}\n\n/**\n * Unsubscribe from the channel.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nChannel.prototype.unsubscribe = function (callback) {\n    this.client.unsubscribe(this.name);\n    if (typeof callback === 'function') {\n        this.on('unsubscribe', callback);\n    }\n    return this;\n}\n"
  },
  {
    "path": "lib/Redback.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar redis = require('redis'),\n    Structure = require('./Structure'),\n    Channel = require('./Channel').Channel,\n    Cache = require('./Cache').Cache;\n\n/**\n * Define the available Redis structures.\n */\n\nvar base = ['Hash','List','Set','SortedSet','Bitfield'];\n\n/**\n * Define the available advanced structures.\n */\n\nvar advanced = ['KeyPair','DensitySet','CappedList','SocialGraph',\n                'Queue', 'RateLimit', 'BloomFilter', 'Lock'];\n\n/**\n * The Redback object wraps the Redis client and acts as a factory\n * for structures.\n *\n * @param {RedisClient} client\n * @param {Object} options (optional)\n * or\n * @param {int} port (optional)\n * @param {string} host (optional)\n * @param {Object} options (optional)\n * @api public\n */\n\nvar Redback = exports.Redback = function (client, options) {\n    if (typeof client === 'object' && client) {\n        this.client = client;\n    } else {\n        this.client = redis.createClient.apply(this, arguments);\n        options = arguments[1] instanceof Object ?\n            arguments[1] : arguments[2];\n    }\n    this.namespace = '';\n    if (typeof options === 'object' && options.namespace) {\n        this.namespace = options.namespace;\n    }\n}\n\n/**\n * Make a structure available to the client.\n *\n * @param {string} name\n * @param {Function|Object} Structure\n * @api private\n */\n\nRedback.prototype.addStructure = function (name, obj) {\n    if (typeof obj !== 'function') {\n        obj = Structure.new(obj);\n    }\n    exports[name] = obj;\n    Redback.prototype['create' + name] = function (key) {\n        var init_args = Array.prototype.slice.call(arguments, 1);\n        return new obj(this.client, key, this.namespace, init_args);\n    }\n}\n\n/**\n * Create a new Cache.\n *\n * @param {string} namespace (optional)\n * @return Cache\n * @api public\n */\n\nRedback.prototype.createCache = function (namespace) {\n    namespace = namespace || 'cache';\n    if (this.namespace.length) {\n        namespace = this.namespace + ':' + namespace;\n    }\n    return new Cache(this.client, namespace);\n}\n\n/**\n * Create a new Channel.\n *\n * @param {string} channel - the channel name\n * @return Channel\n * @api public\n */\n\nRedback.prototype.createChannel = function (channel) {\n    if (!channel) {\n        throw new Error('A channel key is required');\n    }\n    if (this.namespace.length) {\n        channel = this.namespace + ':' + channel;\n    }\n    return new Channel(this.client, channel);\n}\n\n/**\n * Send a (BG)SAVE command to Redis.\n *\n * @param {string} background (optional - default is false)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nRedback.prototype.save = function (background, callback) {\n    if (typeof background === 'function') {\n        callback = background;\n        this.client.save(callback);\n    } else {\n        this.client.bgsave(callback);\n    }\n    return this;\n}\n\n/**\n * Close the connection to Redis.\n *\n * @return this\n * @api public\n */\n\nRedback.prototype.quit = function () {\n    this.client.quit();\n    return this;\n}\n\n/**\n * Create a new Redback client.\n *\n * @param {int} port (optional)\n * @param {string} host (optional)\n * @param {Object} options (optional)\n * @api public\n */\n\nexports.createClient = function (port, host, options) {\n    return new Redback(port, host, options);\n}\n\n/**\n * Wrap a Redis client with Redback.\n *\n * @param {RedisClient} client\n * @param {Object} options (optional)\n * @api public\n */\n\nexports.use = function (client, options) {\n    return new Redback(client, options);\n}\n\n/**\n * Add the Redis structures from ./base_structures\n */\n\nbase.forEach(function (structure) {\n    Redback.prototype.addStructure(structure,\n        require('./base_structures/' + structure)[structure]);\n});\n\n/**\n * Add the advanced structures from ./advanced_structures\n */\n\nadvanced.forEach(function (structure) {\n    Redback.prototype.addStructure(structure,\n        require('./advanced_structures/' + structure)[structure]);\n});\n\n/**\n * Redis constants.\n */\n\nRedback.prototype.INF  = exports.INF = '+inf';\nRedback.prototype.NINF = exports.NINF = '-inf';\n\n/**\n * Export prototypes so that they can be extended.\n */\n\nexports.Client = redis.RedisClient;\nexports.Structure = Structure.Structure;\nexports.Cache = Cache;\nexports.Channel = Channel;\n"
  },
  {
    "path": "lib/Structure.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * All Redback structures inherit from this.\n */\n\nvar Structure = exports.Structure = function () {};\n\n/**\n * Create a new Structure by extending the base Structure.\n *\n * @param {Object} methods (optional)\n * @return structure\n * @api public\n */\n\nexports.new = function (methods) {\n    return Structure.prototype.extend(methods);\n}\n\n/**\n * Expire the structure after a certain number of seconds.\n *\n * @param {int} ttl\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nStructure.prototype.expire = function (ttl, callback) {\n    callback = callback || function () {};\n    this.client.expire(this.key, ttl, callback);\n    return this;\n}\n\n/**\n * Expire the structure at a certain date.\n *\n * @param {Date} when\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nStructure.prototype.expireAt = function (when, callback) {\n    callback = callback || function () {};\n    if (typeof when.getTime === 'function') {\n        when = Math.round(when.getTime() / 1000); //ms => s\n    }\n    this.client.expireat(this.key, when, callback);\n    return this;\n}\n\n/**\n * Get the number of seconds before the structure expires.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.ttl = function (callback) {\n    this.client.ttl(this.key, callback);\n    return this;\n}\n\n/**\n * Checks whether the structure has an expiry.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.isVolatile = function (callback) {\n    this.client.ttl(this.key, function (err, ttl) {\n        if (err) return callback(err, null);\n        callback(null, ttl != -1);\n    });\n    return this;\n}\n\n/**\n * Remove the structure's associated expiry.\n *\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nStructure.prototype.persist = function (callback) {\n    callback = callback || function () {};\n    this.client.persist(this.key, callback);\n    return this;\n}\n\n/**\n * Remove the structure from the Redis database.\n *\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nStructure.prototype.destroy =\nStructure.prototype.flush = function (callback) {\n    callback = callback || function () {};\n    this.client.del(this.key, callback);\n    return this;\n}\n\n/**\n * A helper for creating atomically auto-incrementing keys.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.autoincrement = function (callback) {\n    var key = this.key + ':_autoinc',\n        multi = this.client.multi();\n    multi.setnx(key, 1).get(key).incr(key);\n    multi.exec(function (err, replies) {\n        if (err) return callback(err, null);\n        callback(null, replies[1]);\n    });\n    return this;\n}\n\n/**\n * Takes a redback structure or key string and returns the key.\n *\n * @param {string|Object} key\n * @return {string} key\n * @api public\n */\n\nStructure.prototype.getKey = function (key, which) {\n    which = which || 'key';\n    if (typeof key[which] !== 'undefined') {\n        return key[which];\n    }\n    return key;\n}\n\n/**\n * A helper that extracts the Redis keys from many Structure or string arguments.\n *\n * @param {Array} structures\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.getKeys = function (structures, which) {\n    var structures = Array.prototype.slice.call(structures),\n        callback = structures.pop(),\n        self = this,\n        keys = [];\n    for (var i = 0, l = structures.length; i < l; i++) {\n        if (Array.isArray(structures[i])) {\n            structures[i].forEach(function (structure) {\n                keys.push(self.getKey(structure, which));\n            });\n        } else {\n            keys.push(this.getKey(structures[i], which));\n        }\n    }\n    keys.push(callback);\n    return keys;\n}\n\n/**\n * Add the namespace on to a key.\n *\n * @param {string} key\n * @return {string} namespaced_key\n * @api public\n */\n\nStructure.prototype.namespaceKey = function (key) {\n    key = key || '';\n    if (this.namespace.length) {\n        key = this.namespace + ':' + key;\n    }\n    return key;\n}\n\n/**\n * Extend the structure.\n *\n * @param {Object} methods (optional)\n * @return this\n * @api public\n */\n\nStructure.prototype.extend = function (methods) {\n    var structure = function (client, key, namespace, init_args) {\n        this.client = client;\n        this.namespace = namespace || '';\n        if (!key) {\n            throw new Error('A key is required');\n        }\n        if (Array.isArray(key)) {\n            key = key.join(':');\n        }\n        this.id = key;\n        if (this.namespace.length) {\n            key = this.namespace + ':' + key;\n        }\n        this.key = key;\n        if (typeof this.init === 'function') {\n            this.init.apply(this, init_args);\n        }\n    }, ctor = function () {\n        this.constructor = structure;\n    }\n    ctor.prototype = this;\n    structure.prototype = new ctor;\n    structure.__super__ = this;\n    if (typeof methods === 'object') {\n        for (var i in methods) {\n            structure.prototype[i] = methods[i];\n        }\n    }\n    return structure;\n}\n\n\n/**\n * Create a random key for temporary use.\n *\n * @return {string} random_key\n * @api public\n */\n\nStructure.prototype.randomKey = function () {\n    return Math.random();\n}\n\n/**\n * Get the type of the current structure.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.type = function (callback) {\n    this.client.type(this.key, callback);\n    return this;\n}\n\n/**\n * Rename the structure (change the Redis key).\n *\n * @param {string} new_key\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.rename = function (new_key, callback) {\n    var self = this;\n    new_key = this.namespaceKey(new_key);\n    this.client.rename(this.key, new_key, function (err) {\n        if (err) return callback(err, null);\n        self.key = new_key;\n        callback();\n    });\n    return this;\n}\n\n/**\n * Sort all elements in the structure.\n *\n * Options:\n *    limit, offset, by, get, alpha, desc, store\n *\n * Reference:\n *    http://redis.io/commands/sort\n *\n * @param {object} options\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nStructure.prototype.sort = function (options, callback) {\n    var args = [this.key];\n\n    //SORT key [BY pattern] [LIMIT offset count]\n    //   [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination]\n    if (typeof options.by !== 'undefined') {\n        args.push('BY', options.by);\n    }\n    if (typeof options.limit !== 'undefined') {\n        args.push('LIMIT');\n        if (typeof options.offset !== 'undefined') {\n            args.push(options.offset);\n        }\n        args.push(options.limit);\n    }\n    if (typeof options.get !== 'undefined') {\n        if (Array.isArray(options.get)) {\n            options.get.forEach(function (pattern) {\n                args.push('GET', pattern);\n            });\n        } else {\n            args.push('GET', options.get);\n        }\n    }\n    if (typeof options.desc !== 'undefined' && options.desc) {\n        args.push('DESC');\n    }\n    if (typeof options.alpha !== 'undefined' && options.alpha) {\n        args.push('ALPHA');\n    }\n    if (typeof options.store !== 'undefined') {\n        args.push('STORE', options.store);\n    }\n    this.client.sort.apply(this.client, args);\n    return this;\n}\n"
  },
  {
    "path": "lib/Utils.js",
    "content": "/*\n===============================================================================\nCrc32 is a JavaScript function for computing the CRC32 of a string\n...............................................................................\n\nVersion: 1.2 - 2006/11 - http://noteslog.com/category/javascript/\n\n-------------------------------------------------------------------------------\nCopyright (c) 2006 Andrea Ercolino\nhttp://www.opensource.org/licenses/mit-license.php\n===============================================================================\n*/\n\nexports.crc32 = function(str, crc) {\n  if(crc == undefined) crc = 0;\n  var n = 0; //a number between 0 and 255\n  var x = 0; //an hex number\n\n  crc = crc ^ (-1);\n  for( var i = 0, iTop = str.length; i < iTop; i++ ) {\n    n = ( crc ^ str.charCodeAt( i ) ) & 0xFF;\n    x = \"0x\" + table.substr( n * 9, 8 );\n    crc = ( crc >>> 8 ) ^ x;\n  }\n  return Math.abs(crc ^ (-1));\n};\nvar table = \"00000000 77073096 EE0E612C 990951BA 076DC419 706AF48F E963A535 9E6495A3 0EDB8832 79DCB8A4 E0D5E91E 97D2D988 09B64C2B 7EB17CBD E7B82D07 90BF1D91 1DB71064 6AB020F2 F3B97148 84BE41DE 1ADAD47D 6DDDE4EB F4D4B551 83D385C7 136C9856 646BA8C0 FD62F97A 8A65C9EC 14015C4F 63066CD9 FA0F3D63 8D080DF5 3B6E20C8 4C69105E D56041E4 A2677172 3C03E4D1 4B04D447 D20D85FD A50AB56B 35B5A8FA 42B2986C DBBBC9D6 ACBCF940 32D86CE3 45DF5C75 DCD60DCF ABD13D59 26D930AC 51DE003A C8D75180 BFD06116 21B4F4B5 56B3C423 CFBA9599 B8BDA50F 2802B89E 5F058808 C60CD9B2 B10BE924 2F6F7C87 58684C11 C1611DAB B6662D3D 76DC4190 01DB7106 98D220BC EFD5102A 71B18589 06B6B51F 9FBFE4A5 E8B8D433 7807C9A2 0F00F934 9609A88E E10E9818 7F6A0DBB 086D3D2D 91646C97 E6635C01 6B6B51F4 1C6C6162 856530D8 F262004E 6C0695ED 1B01A57B 8208F4C1 F50FC457 65B0D9C6 12B7E950 8BBEB8EA FCB9887C 62DD1DDF 15DA2D49 8CD37CF3 FBD44C65 4DB26158 3AB551CE A3BC0074 D4BB30E2 4ADFA541 3DD895D7 A4D1C46D D3D6F4FB 4369E96A 346ED9FC AD678846 DA60B8D0 44042D73 33031DE5 AA0A4C5F DD0D7CC9 5005713C 270241AA BE0B1010 C90C2086 5768B525 206F85B3 B966D409 CE61E49F 5EDEF90E 29D9C998 B0D09822 C7D7A8B4 59B33D17 2EB40D81 B7BD5C3B C0BA6CAD EDB88320 9ABFB3B6 03B6E20C 74B1D29A EAD54739 9DD277AF 04DB2615 73DC1683 E3630B12 94643B84 0D6D6A3E 7A6A5AA8 E40ECF0B 9309FF9D 0A00AE27 7D079EB1 F00F9344 8708A3D2 1E01F268 6906C2FE F762575D 806567CB 196C3671 6E6B06E7 FED41B76 89D32BE0 10DA7A5A 67DD4ACC F9B9DF6F 8EBEEFF9 17B7BE43 60B08ED5 D6D6A3E8 A1D1937E 38D8C2C4 4FDFF252 D1BB67F1 A6BC5767 3FB506DD 48B2364B D80D2BDA AF0A1B4C 36034AF6 41047A60 DF60EFC3 A867DF55 316E8EEF 4669BE79 CB61B38C BC66831A 256FD2A0 5268E236 CC0C7795 BB0B4703 220216B9 5505262F C5BA3BBE B2BD0B28 2BB45A92 5CB36A04 C2D7FFA7 B5D0CF31 2CD99E8B 5BDEAE1D 9B64C2B0 EC63F226 756AA39C 026D930A 9C0906A9 EB0E363F 72076785 05005713 95BF4A82 E2B87A14 7BB12BAE 0CB61B38 92D28E9B E5D5BE0D 7CDCEFB7 0BDBDF21 86D3D2D4 F1D4E242 68DDB3F8 1FDA836E 81BE16CD F6B9265B 6FB077E1 18B74777 88085AE6 FF0F6A70 66063BCA 11010B5C 8F659EFF F862AE69 616BFFD3 166CCF45 A00AE278 D70DD2EE 4E048354 3903B3C2 A7672661 D06016F7 4969474D 3E6E77DB AED16A4A D9D65ADC 40DF0B66 37D83BF0 A9BCAE53 DEBB9EC5 47B2CF7F 30B5FFE9 BDBDF21C CABAC28A 53B39330 24B4A3A6 BAD03605 CDD70693 54DE5729 23D967BF B3667A2E C4614AB8 5D681B02 2A6F2B94 B40BBE37 C30C8EA1 5A05DF1B 2D02EF8D\";\n\n"
  },
  {
    "path": "lib/advanced_structures/BloomFilter.js",
    "content": "/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure'),\n    crc32 = require('../Utils').crc32;\n\n/**\n * A Simple BloomFilter. Bloomfilter is a probabilistic data structure used to\n * determine if an element is present in a set. There may be false positives,\n * but there cannot be false negatives.\n *\n * Usage:\n *    `redback.createBloomFilter(key [, size, hashes]);`\n *\n * Options:\n *    `size` - Size of the bloom filter , default is 100 bits.\n *    `hashes` - Number of hashes to perform. default is 2.\n *\n * Reference:\n *    http://redis.io/commands#string\n *    http://en.wikipedia.org/wiki/Bloom_filter\n *    http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html\n *\n * Redis Structure:\n *    `(namespace:)key = string(bits)`\n */\n\nvar BloomFilter = exports.BloomFilter = Structure.new();\n\n/**\n * Initialise the bloom filter.\n *\n * @param {int} size (optional) - Size of bloom filter.\n * @param {int} num_hashes(optional) - Number of hashes to perform while storing.\n * @api private\n */\n\nBloomFilter.prototype.init = function(size, num_hashes) {\n    this.num_hashes = num_hashes || 2;\n    this.size = size || 100;\n}\n\n/**\n * Adds an element to the bloom filter.\n *\n * @param {string} item - Item to store into bloom filter\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nBloomFilter.prototype.add = function(item, callback) {\n    var multi = this.client.multi(), crc;\n\n    for (var hash_index = 0; hash_index < this.num_hashes; hash_index++) {\n        crc = crc32(item, hash_index) % (this.size+1);\n        multi.setbit(this.key, crc, 1);\n    }\n    multi.exec(callback || function () {});\n    return this;\n}\n\n/**\n * Checks if the element exists in the bloom filter. \n * This can return false positives( i.e An element does not exist but it returns true)\n * But this can never return false negatives. (i.e an element )\n *\n * @param {string} item - Item to check for existence in bloom filter\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nBloomFilter.prototype.exists = function(item, callback) {\n    var multi = this.client.multi(), crc;\n    callback = callback || function () {};\n\n    for (var hash_index = 0; hash_index < this.num_hashes; hash_index++) {\n        crc = crc32(item, hash_index) % (this.size+1);\n        multi.getbit(this.key, crc);\n    }\n\n    multi.exec(function(err, results) {\n        callback(err, results.indexOf(0) === -1);\n    });\n\n    return this;\n}\n\n/**\n * Resets the Bloom filter.\n *\n * @param {Function} callback (optional)\n * @return this\n */\n\nBloomFilter.prototype.reset = function (callback) {\n    this.client.set(this.key, 0, callback || function () {});\n    return this;\n}\n"
  },
  {
    "path": "lib/advanced_structures/CappedList.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar List = require('../base_structures/List').List;\n\n/**\n * A Redis list with a fixed length. Each command that adds a value to the\n * list is followed by an `LTRIM` command.\n *\n * Usage:\n *    `redback.createCappedList(key [, max_length]);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#lists\n *    http://redis.io/commands/ltrim\n *\n * Redis Structure:\n *    `(namespace:)key = list(values)`\n */\n\nvar CappedList = exports.CappedList = List.prototype.extend();\n\n/**\n * Setup the Capped List.\n *\n * @param {int} length - the maximum length of the list\n * @param {Function} callback\n * @api private\n */\n\nCappedList.prototype.init = function (length) {\n    this.len = length || 1000;\n}\n\n/**\n * Insert an element before the specified pivot.\n *\n * @param {int} pivot\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCappedList.prototype.insertBefore = function (pivot, value, callback) {\n    callback = callback || function () {};\n    var multi = this.client.multi()\n    multi.linsert(this.key, 'BEFORE', pivot, value);\n    multi.ltrim(this.key, -1 * this.len, -1);\n    multi.exec(callback);\n    return this;\n}\n\n/**\n * Insert an element after the specified pivot.\n *\n * @param {int} pivot\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCappedList.prototype.insertAfter = function (pivot, value, callback) {\n    callback = callback || function () {};\n    var multi = this.client.multi()\n    multi.linsert(this.key, 'AFTER', pivot, value);\n    multi.ltrim(this.key, -1 * this.len, -1);\n    multi.exec(callback);\n    return this;\n}\n\n/**\n * Add one or more elements to the start of the list.\n *\n * @param {string|array} value(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCappedList.prototype.unshift = CappedList.prototype.lpush = function (values, callback) {\n    callback = callback || function () {};\n    var multi = this.client.multi();\n    if (Array.isArray(values)) {\n        var key = this.key;\n        values.reverse().forEach(function (value) {\n            multi.lpush(key, value);\n        });\n    } else {\n        multi.lpush(this.key, values);\n    }\n    multi.ltrim(this.key, 0, this.len - 1);\n    multi.exec(callback);\n    return this;\n}\n\n/**\n * Add one or more elements to the end of the list.\n *\n * @param {string|array} value(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nCappedList.prototype.push = CappedList.prototype.add = function (values, callback) {\n    callback = callback || function () {};\n    var multi = this.client.multi();\n    if (Array.isArray(values)) {\n        var key = this.key;\n        values.forEach(function (value) {\n            multi.rpush(key, value);\n        });\n    } else {\n        multi.rpush(this.key, values);\n    }\n    multi.ltrim(this.key, -1 * this.len, -1);\n    multi.exec(callback);\n    return this;\n}\n"
  },
  {
    "path": "lib/advanced_structures/DensitySet.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar SortedSet = require('../base_structures/SortedSet').SortedSet;\n\n/**\n * The DensitySet is similar to a SortedSet but the ability to explicitly\n * set an element's score has been removed. Instead, adding/removing\n * an element will increment/decrement its score, e.g.\n *     `DensitySet.add(['foo','foo','foo'], ..)` //'foo' has a score of 3\n *\n * Usage:\n *    `redback.createDensitySet(key);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#sorted-sets\n *\n * Redis Structure:\n *    `(namespace:)key = zset(count => element)`\n */\n\nvar DensitySet = exports.DensitySet = SortedSet.prototype.extend();\n\n/**\n * Add one or more elements to the set.\n *\n * @param {string|Array} element(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nDensitySet.prototype.add = function (element, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(element)) {\n        return this.addAll(element, callback);\n    }\n    this.client.zincrby(this.key, 1, element, callback);\n    return this;\n}\n\n/**\n * Remove one or more elements from the set.\n *\n * @param {string|Array} element(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nDensitySet.prototype.remove = function (element, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(element)) {\n        return this.removeAll(element, callback);\n    }\n    var self = this;\n    this.client.zincrby(this.key, -1, element, function (err, removed) {\n        if (err) return callback(err, null);\n        self.client.zremrangebyscore(self.key, '-inf', 0, callback);\n    });\n    return this;\n}\n\n/**\n * Add multiple elements to the set.\n *\n * @param {Array} elements\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nDensitySet.prototype.addAll = function (elements, callback) {\n    var self = this,\n        remaining = elements.length,\n        failed = false,\n        add_count = 0;\n\n    elements.forEach(function (element) {\n        self.client.zincrby(self.key, 1, element, function (err, added) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err);\n            } else {\n                if (added) add_count++;\n                if (!--remaining) callback(null, add_count);\n            }\n        });\n    });\n    return this;\n}\n\n/**\n * Remove multiple elements from the set.\n *\n * @param {Array} elements\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nDensitySet.prototype.removeAll = function (elements, callback) {\n    var self = this,\n        remaining = elements.length,\n        failed = false,\n        rem_count = 0;\n\n    elements.forEach(function (element) {\n        self.client.zincrby(self.key, -1, element, function (err, added) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err);\n            } else {\n                if (added) rem_count++;\n                if (!--remaining) {\n                    self.client.zremrangebyscore(self.key, '-inf', 0, function (err) {\n                        callback(err, rem_count);\n                    });\n                }\n            }\n        });\n    });\n    return this;\n}\n"
  },
  {
    "path": "lib/advanced_structures/KeyPair.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * The KeyPair is a structure where unique values are assigned an\n * ID (like a table with a primary auto-incrementing key and\n * a single unique column). Internally, the KeyPair uses two Redis\n * hashes to provide O(1) lookup by both ID and value.\n *\n * Usage:\n *    `redback.createKeyPair(key);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#hashes\n *\n * Redis Structure:\n *    `(namespace:)key     = hash(id => value)`\n *    `(namespace:)key:ids = hash(value => id)`\n */\n\nvar KeyPair = exports.KeyPair = Structure.new();\n\n/**\n * Initialise the KeyPair.\n *\n * @api private\n */\n\nKeyPair.prototype.init = function () {\n    this.idkey = this.key + ':ids';\n}\n\n/**\n * Add a unique value to the KeyPair and return its id. If the value already\n * exists, the existing id is returned.\n *\n * @param {string|Array} value(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.add = function (value, callback) {\n    //Pass on an array of values to addAll()\n    if (Array.isArray(value)) {\n        return this.addAll(value, callback);\n    }\n\n    var self = this, hashed_value = this.hashValue(value);\n    //Check if the value already has an id\n    this.client.hget(this.idkey, value, function (err, id) {\n        if (err) return callback(err, null);\n        if (null !== id) {\n            callback(null, id);\n        } else {\n            //If not, create a new id\n            self.autoincrement(function (err, id) {\n                if (err) return callback(err, null);\n\n                //Set the id and value simultaneously\n                var multi = self.client.multi();\n                multi.hsetnx(self.idkey, hashed_value, id);\n                multi.hsetnx(self.key, id, value);\n                multi.exec(function(err, response) {\n                    if (err) return callback(err, null);\n\n                    //Another client may have add at exactly the same time, so do\n                    //another get to get the actual stored id\n                    self.client.hget(self.idkey, hashed_value, function (err, real_id) {\n                        if (err) return callback(err, null);\n                        if (real_id == id) {\n                            return callback(null, real_id);\n                        } else {\n                            //Another client did beat us! remove the bad key\n                            self.client.hdel(self.key, id, function (err) {\n                                if (err) {\n                                    callback(err, null);\n                                } else {\n                                    callback(null, real_id);\n                                }\n                            });\n                        }\n                    });\n                });\n            });\n        }\n    });\n    return this;\n}\n\n/**\n * Add multiple unique values to the KeyPair and return and\n * object containing {value: id, ...}.\n *\n * @param {Array} values\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.addAll = function (values, callback) {\n    var self = this,\n        remaining = values.length,\n        ids = {},\n        failed = false;\n\n    values.forEach(function (value) {\n        self.add(value, function (err, id) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err, null);\n            } else {\n                ids[value] = id;\n                if (!--remaining) callback(null, ids);\n            }\n        });\n    });\n}\n\n/**\n * Lookup a unique value and get the associated id.\n *\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.get = function (value, callback) {\n    if (typeof value === 'function') {\n        callback = value;\n        this.client.hgetall(this.key, callback);\n    } else if (Array.isArray(value)) {\n        for (var i = 0, l = value.length; i < l; i++) {\n            value[i] = this.hashValue(value[i]);\n        }\n        this.client.hmget(this.idkey, value, callback)\n    } else {\n        this.client.hget(this.idkey, this.hashValue(value), callback);\n    }\n    return this;\n}\n\n/**\n * Get the value associated with the id.\n *\n * @param {int|Array} id(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.getById = function (id, callback) {\n\tif (Array.isArray(id))\n    \tthis.client.hmget(this.key, id, callback);\n\telse\n    \tthis.client.hget(this.key, id, callback);\n    return this;\n}\n\n/**\n * Get an array of ids.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.ids = function (callback) {\n    this.client.hkeys(this.key, callback);\n    return this;\n}\n\n/**\n * Get an array of values.\n *\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.values = function (callback) {\n    this.client.hvals(this.key, callback);\n    return this;\n}\n\n/**\n * Check whether a unique value already exists and  has an associated id.\n *\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.exists = function (value, callback) {\n    this.client.hexists(this.idkey, this.hashValue(value), callback);\n    return this;\n}\n\n/**\n * Checks whether an id exists.\n *\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.idExists = function (id, callback) {\n    this.client.hexists(this.key, id, callback);\n    return this;\n}\n\n/**\n * Deletes a unique value and its associated id.\n *\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nKeyPair.prototype.delete = function (value, callback) {\n    callback = callback || function () {};\n    var self = this, value = this.hashValue(value);\n    this.client.hget(this.idkey, value, function (err, id) {\n        if (err || value == null) return callback(err);\n        self._delete(id, value, callback);\n    });\n    return this;\n}\n\n/**\n * Deletes an id and its associated unique value.\n *\n * @param {int} id\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nKeyPair.prototype.deleteById = function (id, callback) {\n    callback = callback || function () {};\n    var self = this;\n    this.client.hget(this.key, id, function (err, value) {\n        if (err || value == null) return callback(err);\n        self._delete(id, self.hashValue(value), callback);\n    });\n    return this;\n}\n\n/**\n * An internal helper for simultaneously deleting an id/value pair.\n *\n * @param {int} id\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nKeyPair.prototype._delete = function (id, value, callback) {\n    var multi = this.client.multi();\n    multi.hdel(this.key, id);\n    multi.hdel(this.idkey, this.hashValue(value));\n    multi.exec(callback);\n    return this;\n}\n\n/**\n * Get the number of unique values.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nKeyPair.prototype.length = function (callback) {\n    this.client.hlen(this.key, callback);\n    return this;\n}\n\n/**\n * Override this method if you need to hash the unique value\n * in the second internal hash (i.e. if values are large).\n *\n * @param {string} value\n * @return {string} hashed_value\n * @api public\n */\n\nKeyPair.prototype.hashValue = function (value) {\n    return value;\n}\n"
  },
  {
    "path": "lib/advanced_structures/Lock.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar crypto = require('crypto');\nvar Structure = require('../Structure');\n\n/**\n * A distributed lock.\n */\n\nvar Lock = exports.Lock = Structure.new();\n\n/**\n * Acquire a temporary lock on some key.\n *\n * @param   {string}    key             The unique key of the lock\n * @param   {number}    ttl             The amount of time (in seconds) before the lock expires\n * @param   {Function}  callback        Invoked when the process completes\n * @param   {Error}     callback.err    An error that occurred, if any\n * @param   {string}    callback.token  The token that was acquired if successful. If the lock was\n *                                      not acquired then this will be `undefined`\n * @api public\n */\n\nLock.prototype.acquire = function(key, ttl, callback) {\n    var client = this.client;\n\n    _createToken(function(err, token) {\n        if (err) {\n            return callback(err);\n        }\n\n        client.setnx(key, token, function(err, wasSet) {\n            if (err) {\n                return callback(err);\n            } else if (!wasSet) {\n                // We did not successfully acquire the lock. Since a process can crash after it sets\n                // the lock but before it sets the expiry, we need to avoid deadlocks by ensuring\n                // the lock has a TTL associated to it\n                _ensureTtl(client, key, ttl);\n                return callback();\n            }\n\n            // Apply the expiry to the lock\n            client.expire(key, ttl, function(err) {\n                if (err) {\n                    return callback(err);\n                }\n\n                // Return the token, which is used to release the lock\n                return callback(null, token);\n            });\n        });\n    });\n};\n\n/**\n * Release a lock that was acquired with the provided key and token.\n *\n * @param   {string}    key                 The key for the lock to release\n * @param   {string}    token               The token that was generated for the lock acquisition\n * @param   {Function}  callback            Invoked when the function completes\n * @param   {Error}     callback.err        An error that occurred, if any\n * @param   {boolean}   callback.hadLock    Determines whether or not we owned the lock at the time\n *                                          that we released it\n * @api public\n */\nLock.prototype.release = function(key, token, callback) {\n    var client = this.client;\n\n    client.get(key, function(err, lockedToken) {\n        if (err) {\n            return callback(err);\n        } else if (lockedToken !== token) {\n            // The current token is not the one we acquired. It's possible we held the lock longer\n            // than its expiry\n            return callback(null, false);\n        }\n\n        // We have the token, simply delete the lock key\n        client.del(key, function(err) {\n            if (err) {\n                return callback(err);\n            }\n\n            return callback(null, true);\n        });\n    });\n};\n\n/**\n * Ensure the lock with the given key has a `ttl`. If it does not, the given expiry will be applied\n * to it.\n *\n * @param   {RedisClient}   client  The Redis to use to apply the ttl\n * @param   {string}        key     The key of the lock to check\n * @param   {number}        ttl     If the lock does not have an expiry set, set this duration (in\n *                                  seconds)\n * @api private\n */\n\nvar _ensureTtl = function(client, key, ttl) {\n    client.ttl(key, function(err, currentTtl) {\n        if (currentTtl === -1) {\n            // There is no expiry set on this key, set it\n            client.expire(key, ttl);\n        }\n    });\n};\n\n/**\n * Generate a random lock token.\n *\n * @param   {Function}  callback        Invoked with the token when complete\n * @param   {Error}     callback.err    An error that occurred, if any\n * @param   {string}    callback.token  The randomly generated token\n * @api private\n */\n\nvar _createToken = function(callback) {\n    crypto.randomBytes(16, function(err, buffer) {\n        if (err) {\n            return callback(err);\n        }\n\n        return callback(null, buffer.toString('base64'));\n    });\n};\n"
  },
  {
    "path": "lib/advanced_structures/Queue.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure'),\n    List = require('../base_structures/List').List;\n\n/**\n * A simple FIFO/LIFO queue.\n *\n * Usage:\n *    `redback.createQueue(key [, is_fifo]);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#lists\n *    http://en.wikipedia.org/wiki/Queue_(data_structure)\n *\n * Redis Structure:\n *    `(namespace:)key = list(values)`\n */\n\nvar Queue = exports.Queue = Structure.new();\n\n/**\n * Setup the Queue to be either FIFO or LIFO.\n *\n * @param {bool} is_fifo\n * @api private\n */\n\nQueue.prototype.init = function (is_fifo) {\n    this.fifo = is_fifo;\n    this.list = new List(this.client, this.id, this.namespace);\n}\n\n/**\n * Add one or more elements to the queue.\n *\n * @param {string|Array} value(s)\n * @param {Function} callback (optional)\n * @api public\n */\n\nQueue.prototype.enqueue = Queue.prototype.add = function (values, callback) {\n    this.list.unshift(values, callback);\n    return this;\n}\n\n/**\n * Remove the next element from the queue.\n *\n * @param {int} wait (optional) - block for this many seconds\n * @param {Function} callback\n * @api public\n */\n\nQueue.prototype.dequeue = Queue.prototype.next = function (wait, callback) {\n    this.list[this.fifo ? 'pop' : 'shift'](wait, callback);\n    return this;\n}\n"
  },
  {
    "path": "lib/advanced_structures/RateLimit.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * See https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da\n *\n * Count the number of times a subject performs an action over an interval\n * in the immediate past - this can be used to rate limit the subject if\n * the count goes over a certain threshold. For example, you could track\n * how many times an IP (the subject) has viewed a page (the action) over\n * a certain time frame and limit them accordingly.\n *\n * Usage:\n *    `redback.createRateLimit(action [, options]);`\n *\n * Options:\n *    `bucket_interval` - default is 5 seconds\n *    `bucket_span`     - default is 10 minutes\n *    `subject_expiry`  - default is 20 minutes\n *\n * Reference:\n *    https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da\n *    http://redis.io/topics/data-types#hash\n *\n * Redis Structure:\n *    `(namespace:)action:<subject1> = hash(bucket => count)`\n *    `(namespace:)action:<subject2> = hash(bucket => count)`\n *    `(namespace:)action:<subjectN> = hash(bucket => count)`\n */\n\nvar RateLimit = exports.RateLimit = Structure.new();\n\n/**\n * Setup the RateLimit structure.\n *\n * @param {Object} options (optional)\n * @api private\n */\n\nRateLimit.prototype.init = function (options) {\n    options = options || {};\n    this.bucket_span = options.bucket_span || 600;\n    this.bucket_interval = options.bucket_interval || 5;\n    this.subject_expiry = options.subject_expiry || 1200;\n    this.bucket_count = Math.round(this.bucket_span / this.bucket_interval);\n}\n\n/**\n * Get the bucket associated with the current time.\n *\n * @param {int} time (optional) - default is the current time (ms since epoch)\n * @return {int} bucket\n * @api private\n */\n\nRateLimit.prototype.getBucket = function (time) {\n    time = (time || new Date().getTime()) / 1000;\n    return Math.floor((time % this.bucket_span) / this.bucket_interval);\n}\n\n/**\n * Increment the count for the specified subject.\n *\n * @param {string} subject\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nRateLimit.prototype.add = function (subject, callback) {\n    if (Array.isArray(subject)) {\n        return this.addAll(subject, callback);\n    }\n    var bucket = this.getBucket(), multi = this.client.multi();\n    subject = this.key + ':' + subject;\n\n    //Increment the current bucket\n    multi.hincrby(subject, bucket, 1)\n\n    //Clear the buckets ahead\n    multi.hdel(subject, (bucket + 1) % this.bucket_count)\n         .hdel(subject, (bucket + 2) % this.bucket_count)\n\n    //Renew the key TTL\n    multi.expire(subject, this.subject_expiry);\n\n    multi.exec(function (err) {\n        if (!callback) return;\n        if (err) return callback(err);\n        callback(null);\n    });\n\n    return this;\n}\n\n/**\n * Count the number of times the subject has performed an action\n * in the last `interval` seconds.\n *\n * @param {string} subject\n * @param {int} interval\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nRateLimit.prototype.count = function (subject, interval, callback) {\n    var bucket = this.getBucket(),\n        multi = this.client.multi(),\n        count = Math.floor(interval / this.bucket_interval);\n\n    subject = this.key + ':' + subject;\n\n    //Get the counts from the previous `count` buckets\n    multi.hget(subject, bucket);\n    while (count--) {\n        multi.hget(subject, (--bucket + this.bucket_count) % this.bucket_count);\n    }\n\n    //Add up the counts from each bucket\n    multi.exec(function (err, counts) {\n        if (err) return callback(err, null);\n        for (var count = 0, i = 0, l = counts.length; i < l; i++) {\n            if (counts[i]) {\n                count += parseInt(counts[i], 10);\n            }\n        }\n        callback(null, count);\n    });\n\n    return this;\n}\n\n/**\n * An alias for `ratelimit.add(subject).count(subject, interval);`\n *\n * @param {string} subject\n * @param {int} interval\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nRateLimit.prototype.addCount = function (subject, interval, callback) {\n    var bucket = this.getBucket(),\n        multi = this.client.multi(),\n        count = Math.floor(interval / this.bucket_interval);\n\n    subject = this.key + ':' + subject;\n\n    //Increment the current bucket\n    multi.hincrby(subject, bucket, 1)\n\n    //Clear the buckets ahead\n    multi.hdel(subject, (bucket + 1) % this.bucket_count)\n         .hdel(subject, (bucket + 2) % this.bucket_count)\n\n    //Renew the key TTL\n    multi.expire(subject, this.subject_expiry);\n\n    //Get the counts from the previous `count` buckets\n    multi.hget(subject, bucket);\n    while (count--) {\n        multi.hget(subject, (--bucket + this.bucket_count) % this.bucket_count);\n    }\n\n    //Add up the counts from each bucket\n    multi.exec(function (err, counts) {\n        if (err) return callback(err, null);\n        for (var count = 0, i = 4, l = counts.length; i < l; i++) {\n            if (counts[i]) {\n                count += parseInt(counts[i], 10);\n            }\n        }\n        callback(null, count);\n    });\n\n    return this;\n}\n"
  },
  {
    "path": "lib/advanced_structures/SocialGraph.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * Build a social graph similar to Twitter's. User ID can be a string or\n * integer, as long as they're unique.\n *\n * Usage:\n *    `redback.createSocialGraph(id [, prefix]);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#sets\n *\n * Redis Structure:\n *    `(namespace:)(prefix:)id:following = set(ids)`\n *    `(namespace:)(prefix:)id:followers = set(ids)`\n */\n\nvar SocialGraph = exports.SocialGraph = Structure.new();\n\n/**\n * Initialise the SocialGraph.\n *\n * @param {string} prefix (optional)\n * @api private\n */\n\nSocialGraph.prototype.init = function (prefix) {\n    this.key_prefix = this.namespaceKey();\n    if (prefix) {\n        this.key_prefix += prefix + ':';\n    }\n    this.key = this.key_prefix + this.id;\n    this.following = this.key + ':following';\n    this.followers = this.key + ':followers';\n}\n\n/**\n * Follow one or more users.\n *\n * @param {int|SocialGraph|Array} user(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.follow = function (users, callback) {\n    var self = this,\n        users = this.getKeys(arguments, 'id'),\n        multi = this.client.multi();\n    if (typeof users[users.length-1] === 'function') {\n        callback = users.pop();\n    } else {\n        callback = function () {};\n    }\n    users.forEach(function (user) {\n        multi.sadd(self.key_prefix + user + ':followers', self.id);\n        multi.sadd(self.following, user);\n    });\n    multi.exec(callback);\n    return this;\n}\n\n/**\n * Unfollow one or more users.\n *\n * @param {int|SocialGraph|Array} user(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.unfollow = function (users, callback) {\n    var self = this,\n        users = this.getKeys(arguments, 'id'),\n        multi = this.client.multi();\n    if (typeof users[users.length-1] === 'function') {\n        callback = users.pop();\n    } else {\n        callback = function () {};\n    }\n    users.forEach(function (user) {\n        multi.srem(self.key_prefix + user + ':followers', self.id);\n        multi.srem(self.following, user);\n    });\n    multi.exec(callback);\n    return this;\n}\n\n/**\n * Gets the users whom the current users follows as an array.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.getFollowing = function (callback) {\n    this.client.smembers(this.following, callback);\n    return this;\n}\n\n/**\n * Gets an array of users who follow the current user.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.getFollowers = function (callback) {\n    this.client.smembers(this.followers, callback);\n    return this;\n}\n\n/**\n * Count how many users the current user follows.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.countFollowing = function (callback) {\n    this.client.scard(this.following, callback);\n    return this;\n}\n\n/**\n * Count how many users follow the current user.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.countFollowers = function (callback) {\n    this.client.scard(this.followers, callback);\n    return this;\n}\n\n/**\n * Checks whether the current user follows the specified user.\n *\n * @param {string|SocialGraph} user\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.isFollowing = function (user, callback) {\n    user = this.getKey(user, 'id');\n    this.client.sismember(this.following, user, callback);\n    return this;\n}\n\n/**\n * Checks whether the specified user follows the current user.\n *\n * @param {string|SocialGraph} user\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.hasFollower = function (user, callback) {\n    user = this.getKey(user, 'id');\n    this.client.sismember(this.followers, user, callback);\n    return this;\n}\n\n/**\n * Gets an array of common followers for one or more users.\n *\n * @param {string|SocialGraph|Array} user(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.getCommonFollowers = function (users, callback) {\n    var users = this.getSocialKeys(arguments, 'followers');\n    users.unshift(this.followers);\n    this.client.sinter.apply(this.client, users);\n    return this;\n}\n\n/**\n * Gets an array of users who are followed by all of the specified user(s).\n *\n * @param {string|SocialGraph|Array} user(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.getCommonFollowing = function (users, callback) {\n    var users = this.getSocialKeys(arguments, 'following');\n    users.unshift(this.following);\n    this.client.sinter.apply(this.client, users);\n    return this;\n}\n\n/**\n * Gets an array of users who follow the current user but do not follow any\n * of the other specified users.\n *\n * @param {string|SocialGraph|Array} user(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.getDifferentFollowers = function (users, callback) {\n    var users = this.getSocialKeys(arguments, 'followers');\n    users.unshift(this.followers);\n    this.client.sdiff.apply(this.client, users);\n    return this;\n}\n\n/**\n * Gets an array of users who are followed by the current user but not any of\n * the other specified users.\n *\n * @param {string|SocialGraph|Array} user(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSocialGraph.prototype.getDifferentFollowing = function (users, callback) {\n    var users = this.getSocialKeys(arguments, 'following');\n    users.unshift(this.following);\n    this.client.sdiff.apply(this.client, users);\n    return this;\n}\n\n/**\n * Grabs the specified SocialGraph key from a list of arguments.\n *\n * @param {Array} args\n * @param {string} key\n * @return {string} social_keys\n * @api private\n */\n\nSocialGraph.prototype.getSocialKeys = function (args, key) {\n    var users = Array.prototype.slice.call(args),\n        callback = users.pop(),\n        user_key,\n        self = this,\n        keys = [];\n\n    for (var i = 0, l = users.length; i < l; i++) {\n        if (Array.isArray(users[i])) {\n            users[i].forEach(function (user) {\n                if (typeof user[key] !== 'undefined') {\n                    user_key = user[key];\n                } else {\n                    user_key = self.key_prefix + user + ':' + key;\n                }\n                keys.push(user_key);\n            });\n        } else {\n            if (typeof users[i][key] !== 'undefined') {\n                user_key = users[i][key];\n            } else {\n                user_key = self.key_prefix + users[i] + ':' + key;\n            }\n            keys.push(user_key);\n        }\n    }\n    keys.push(callback);\n    return keys;\n}\n"
  },
  {
    "path": "lib/base_structures/Bitfield.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * Wrap the Redis bit commands.\n *\n * Usage:\n *    `redback.createBitfield(key);`\n *\n * Reference:\n *    http://redis.io/commands#string\n *\n * Redis Structure:\n *    `(namespace:)key = string`\n */\n\nvar Bitfield = exports.Bitfield = Structure.new();\n\n/**\n * Get a single bit\n *\n * @param {int} bit\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nBitfield.prototype.get = function (bit, callback) {\n    callback = callback || function () {};\n    this.client.getbit(this.key, bit, callback);\n    return this;\n}\n\n/**\n * Set a single bit. The callback receives the previous value.\n *\n * @param {int} bit\n * @param {bool} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nBitfield.prototype.set = function (bit, value, callback) {\n    callback = callback || function () {};\n    this.client.setbit(this.key, bit, value ? 1 : 0, callback);\n    return this;\n}\n"
  },
  {
    "path": "lib/base_structures/Hash.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * A wrapper for the Redis hash type.\n *\n * Usage:\n *    `redback.createHash(key);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#hashes\n *\n * Redis Structure:\n *    `(namespace:)key = hash(key => value)`\n */\n\nvar Hash = exports.Hash = Structure.new();\n\n/**\n * Get an array of hash keys.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nHash.prototype.keys = function (callback) {\n    this.client.hkeys(this.key, callback);\n    return this;\n}\n\n/**\n * Get an array of hash values.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nHash.prototype.values = function (callback) {\n    this.client.hvals(this.key, callback);\n    return this;\n}\n\n/**\n * Get the number of hash keys.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nHash.prototype.length = function (callback) {\n    this.client.hlen(this.key, callback);\n    return this;\n}\n\n/**\n * Delete a hash key.\n *\n * @param {string} hash_key\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nHash.prototype.delete = Hash.prototype.del = function (hash_key, callback) {\n    callback = callback || function () {};\n    this.client.hdel(this.key, hash_key, callback);\n    return this;\n}\n\n/**\n * Checks whether a hash key exists.\n *\n * @param {string} hash_key\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nHash.prototype.exists = function (hash_key, callback) {\n    this.client.hexists(this.key, hash_key, callback);\n    return this;\n}\n\n/**\n * Sets one or more key/value pairs.\n *\n * To set one key/value pair:\n *    `hash.set('foo', 'bar', callback);`\n *\n * To set multiple:\n *    `hash.set({key1:'value1', key2:'value2}, callback);`\n *\n * @param {string|Object} hash_key\n * @param {string} value (optional)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nHash.prototype.set = function (hash_key, value, callback) {\n    if (typeof hash_key === 'object') {\n        callback = value || function () {};\n        this.client.hmset(this.key, hash_key, callback);\n    } else {\n        callback = callback || function () {};\n        this.client.hset(this.key, hash_key, value, callback);\n    }\n    return this;\n}\n\n/**\n * Sets a key/value pair if the key doesn't already exist.\n *\n * @param {string} hash_key\n * @param {string} value\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nHash.prototype.add = function (hash_key, value, callback) {\n    callback = callback || function () {};\n    this.client.hsetnx(this.key, hash_key, value, callback);\n    return this;\n}\n\n/**\n * Gets one or more key/value pairs.\n *\n * To get all key/value pairs in the hash:\n *    `hash.get('foo', callback);`\n *\n * To get certain key/value pairs:\n *    `hash.get(['foo','bar'], callback);`\n *    `hash.get('foo', callback);`\n *\n * @param {string} hash_key (optional)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nHash.prototype.get = function (hash_key, callback) {\n    if (typeof hash_key === 'function') {\n        callback = hash_key;\n        this.client.hgetall(this.key, callback);\n    } else if (Array.isArray(hash_key)) {\n        this.client.hmget(this.key, hash_key, callback)\n    } else {\n        this.client.hget(this.key, hash_key, callback);\n    }\n    return this;\n}\n\n/**\n * Increment the specified hash value.\n *\n * @param {string} hash_key\n * @param {int} amount (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nHash.prototype.increment =\nHash.prototype.incrBy = function (hash_key, amount, callback) {\n    callback = callback || function () {};\n    if (typeof amount === 'function') {\n        callback = amount;\n        amount = 1;\n    }\n    this.client.hincrby(this.key, hash_key, amount, callback);\n    return this;\n}\n\n/**\n * Decrement the specified hash value.\n *\n * @param {string} hash_key\n * @param {int} amount (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nHash.prototype.decrement =\nHash.prototype.decrBy = function (hash_key, amount, callback) {\n    callback = callback || function () {};\n    if (typeof amount === 'function') {\n        callback = amount;\n        amount = 1;\n    }\n    this.client.hincrby(this.key, hash_key, -1 * amount, callback);\n    return this;\n}\n"
  },
  {
    "path": "lib/base_structures/List.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * A wrapper for the Redis list type.\n *\n * Usage:\n *    `redback.createList(key);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#lists\n *\n * Redis Structure:\n *    `(namespace:)key = list(values)`\n */\n\nvar List = exports.List = Structure.new();\n\n/**\n * Get the list as an array.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nList.prototype.values = function (callback) {\n    this.client.lrange(this.key, 0, -1, callback);\n    return this;\n}\n\n/**\n * Get a range of list elements.\n *\n * @param {int} start\n * @param {count} end (optional - defaults to the last element)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nList.prototype.range = function (start, end, callback) {\n    if (typeof end === 'function') {\n        callback = end;\n        end = -1;\n    }\n    this.client.lrange(this.key, start, end, callback);\n    return this;\n}\n\n/**\n * Get one or more elements starting at the specified index.\n *\n * @param {int} index\n * @param {count} count (optional - default is 1)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nList.prototype.get = function (index, count, callback) {\n    if (typeof count === 'function') {\n        callback = count;\n        this.client.lindex(this.key, index, callback);\n    } else {\n        this.client.lrange(this.key, index, index + count - 1, callback);\n    }\n    return this;\n}\n\n/**\n * Cap the length of the list.\n *\n * @param {int} length\n * @param {bool} keep_earliest (optional - default is false)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.cap = function (length, keep_earliest, callback) {\n    callback = callback || function () {};\n    var start = 0, end = -1;\n    if (typeof keep_earliest === 'function') {\n        //Keep the last `length` elements\n        start = -1 * length;\n        callback = keep_earliest;\n    } else {\n        //Keep the first `length` elements\n        end = length - 1;\n    }\n    this.client.ltrim(this.key, start, end, callback);\n    return this;\n}\n\n/**\n * Remove one or more list elements matching the value.\n *\n * @param {string} value\n * @param {bool} count (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.remove = function (value, count, callback) {\n    callback = callback || function () {};\n    if (typeof count === 'function') {\n        callback = count;\n        count = 1;\n    }\n    this.client.lrem(this.key, count, value, callback);\n    return this;\n}\n\n/**\n * Trim a list to the specified bounds.\n *\n * @param {int} start\n * @param {int} end\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.trim = function (start, end, callback) {\n    callback = callback || function () {};\n    this.client.ltrim(this.key, start, end, callback);\n    return this;\n}\n\n/**\n * Insert an element before the specified pivot.\n *\n * @param {int} pivot\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.insertBefore = function (pivot, value, callback) {\n    callback = callback || function () {};\n    this.client.linsert(this.key, 'BEFORE', pivot, value, callback);\n    return this;\n}\n\n/**\n * Insert an element after the specified pivot.\n *\n * @param {int} pivot\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.insertAfter = function (pivot, value, callback) {\n    callback = callback || function () {};\n    this.client.linsert(this.key, 'AFTER', pivot, value, callback);\n    return this;\n}\n\n/**\n * Set the element at the specified index.\n *\n * @param {int} index\n * @param {string} value\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.set = function (index, value, callback) {\n    callback = callback || function () {};\n    this.client.lset(this.key, index, value, callback);\n    return this;\n}\n\n/**\n * Get the number of elements in the list.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nList.prototype.length = function (callback) {\n    this.client.llen(this.key, callback);\n    return this;\n}\n\n/**\n * Get and remove the last element in the list. The first param can be used\n * to block the process and wait until list elements are available. If the list\n * is empty in both examples below, the first example will return `null`, while\n * the second will wait for up to 3 seconds. If a list element becomes available\n * during the 3 seconds it will be returned, otherwise `null` will be returned.\n *\n * Example:\n *    `list.shift(callback);`\n *\n * Blocking Example:\n *    `list.shift(3, callback)`\n *\n * @param {int} wait (optional) - seconds to block\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nList.prototype.shift = function (wait, callback) {\n    if (typeof wait === 'function') {\n        callback = wait;\n        this.client.lpop(this.key, callback);\n    } else {\n        this.client.blpop(this.key, wait, callback);\n    }\n    return this;\n}\n\n/**\n * Get and remove the last element in the list. The first param can be used\n * to block the process and wait until list elements are available. If the list\n * is empty in both examples below, the first example will return `null`, while\n * the second will wait for up to 3 seconds. If a list element becomes available\n * during the 3 seconds it will be returned, otherwise `null` will be returned.\n *\n * Example:\n *    `list.pop(callback);`\n *\n * Blocking Example:\n *    `list.pop(3, callback)`\n *\n * @param {int} wait (optional) - seconds to block\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nList.prototype.pop = function (wait, callback) {\n    if (typeof wait === 'function') {\n        callback = wait;\n        this.client.rpop(this.key, callback);\n    } else {\n        this.client.brpop(this.key, wait, callback);\n    }\n    return this;\n}\n\n/**\n * Add one or more elements to the start of the list.\n *\n * @param {string|array} value(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.unshift = List.prototype.lpush = function (values, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(values)) {\n        var multi = this.client.multi(), key = this.key;\n        values.reverse().forEach(function (value) {\n            multi.lpush(key, value);\n        });\n        multi.exec(callback);\n    } else {\n        this.client.lpush(this.key, values, callback);\n    }\n    return this;\n}\n\n/**\n * Add one or more elements to the end of the list.\n *\n * @param {string|array} value(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.push = List.prototype.add = function (values, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(values)) {\n        var multi = this.client.multi(), key = this.key;\n        values.forEach(function (value) {\n            multi.rpush(key, value);\n        });\n        multi.exec(callback);\n    } else {\n        this.client.rpush(this.key, values, callback);\n    }\n    return this;\n}\n\n/**\n * Remove the last element of the list and add it to the start\n * of another list.\n *\n * @param {String|List} list\n * @param {bool} wait (optional) - seconds to block while waiting\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nList.prototype.popShift = function (list, wait, callback) {\n    callback = callback || function () {};\n    list = this.getKey(list);\n    if (typeof wait === 'function') {\n        callback = wait;\n        this.client.rpoplpush(this.key, list, callback);\n    } else {\n        this.client.brpoplpush(this.key, list, wait, callback);\n    }\n    return this;\n}\n"
  },
  {
    "path": "lib/base_structures/Set.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * A wrapper for the Redis set type.\n *\n * Usage:\n *    `redback.createSet(key);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#sets\n *\n * Redis Structure:\n *    `(namespace:)key = set(elements)`\n */\n\nvar Set = exports.Set = Structure.new();\n\n/**\n * Add one or more elements to the set.\n *\n * @param {string|Array} element(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSet.prototype.add = function (element, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(element)) {\n        return this.addAll(element, callback);\n    }\n    this.client.sadd(this.key, element, callback);\n    return this;\n}\n\n/**\n * Remove one or more elements from the set.\n *\n * @param {string|Array} element(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSet.prototype.remove = function (element, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(element)) {\n        return this.removeAll(element, callback);\n    }\n    this.client.srem(this.key, element, callback);\n    return this;\n}\n\n/**\n * Get an array of elements in the set.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.elements = Set.prototype.members = function (callback) {\n    this.client.smembers(this.key, callback);\n    return this;\n}\n\n/**\n * Move an element to another set.\n *\n * @param {string|Set} dest\n * @param {string} element\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSet.prototype.move = function (dest, element, callback) {\n    callback = callback || function () {};\n    this.client.smove(this.key, this.getKey(dest), element, callback);\n    return this;\n}\n\n/**\n * Check whether an element exists in the set.\n *\n * @param {string} element\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.exists = Set.prototype.contains = function (element, callback) {\n    this.client.sismember(this.key, element, callback);\n    return this;\n}\n\n/**\n * Get the length (cardinality) of the set.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.length = Set.prototype.cardinality = function (callback) {\n    this.client.scard(this.key, callback);\n    return this;\n}\n\n/**\n * Get a random element from the set and optionally remove it.\n *\n * @param {bool} remove (optional - default is false)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.random = function (remove, callback) {\n    if (typeof remove === 'function') {\n        callback = remove;\n        this.client.srandmember(this.key, callback);\n    } else {\n        this.client.spop(this.key, callback);\n    }\n    return this;\n}\n\n/**\n * Get the intersection of one or more sets.\n *\n * @param {string|Set|Array} set(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.inter = function (sets, callback) {\n    sets = this.getKeys(arguments);\n    sets.unshift(this.key);\n    this.client.sinter.apply(this.client, sets);\n    return this;\n}\n\n/**\n * Get the intersection of one or more sets and store it another\n * set (dest).\n *\n * @param {string|Set} dest\n * @param {string|Set|Array} set(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.interStore = function (dest, sets, callback) {\n    sets = this.getKeys(arguments);\n    dest = sets.shift();\n    sets.unshift(dest, this.key);\n    this.client.sinterstore.apply(this.client, sets);\n    return this;\n}\n\n/**\n * Get the union of one or more sets.\n *\n * @param {string|Set|Array} set(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.union = function (sets, callback) {\n    sets = this.getKeys(arguments);\n    sets.unshift(this.key);\n    this.client.sunion.apply(this.client, sets);\n    return this;\n}\n\n/**\n * Get the union of one or more sets and store it another\n * set (dest).\n *\n * @param {string|Set} dest\n * @param {string|Set|Array} set(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.unionStore = function (dest, sets, callback) {\n    sets = this.getKeys(arguments);\n    dest = sets.shift();\n    sets.unshift(dest, this.key);\n    this.client.sunionstore.apply(this.client, sets);\n    return this;\n}\n\n/**\n * Get the difference of one or more sets.\n *\n * @param {string|Set|Array} set(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.diff = function (sets, callback) {\n    sets = this.getKeys(arguments);\n    sets.unshift(this.key);\n    this.client.sdiff.apply(this.client, sets);\n    return this;\n}\n\n/**\n * Get the difference of one or more sets and store it another\n * set (dest).\n *\n * @param {string|Set} dest\n * @param {string|Set|Array} set(s)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSet.prototype.diffStore = function (dest, sets, callback) {\n    sets = this.getKeys(arguments);\n    dest = sets.shift();\n    sets.unshift(dest, this.key);\n    this.client.sdiffstore.apply(this.client, sets);\n    return this;\n}\n\n\n/**\n * Add multiple elements to the set.\n *\n * @param {Array} elements\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nSet.prototype.addAll = function (elements, callback) {\n    var self = this,\n        remaining = elements.length,\n        failed = false,\n        add_count = 0;\n\n    elements.forEach(function (element) {\n        self.client.sadd(self.key, element, function (err, added) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err);\n            } else {\n                if (added) add_count++;\n                if (!--remaining) callback(null, add_count);\n            }\n        });\n    });\n    return this;\n}\n\n/**\n * Remove multiple elements from the set.\n *\n * @param {Array} elements\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nSet.prototype.removeAll = function (elements, callback) {\n    var self = this,\n        remaining = elements.length,\n        failed = false,\n        rem_count = 0;\n\n    elements.forEach(function (element) {\n        self.client.srem(self.key, element, function (err, removed) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err);\n            } else {\n                if (removed) rem_count++;\n                if (!--remaining) callback(null, rem_count);\n            }\n        });\n    });\n    return this;\n}\n"
  },
  {
    "path": "lib/base_structures/SortedSet.js",
    "content": "/*!\n * Redback\n * Copyright(c) 2011 Chris O'Hara <cohara87@gmail.com>\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar Structure = require('../Structure');\n\n/**\n * A wrapper for the Redis sorted set (zset) type. Each element has a\n * score which is used to rank and order all elements in the set. Elements\n * are ranked from lowest score to highest (the lowest score has\n * a rank of 0)\n *\n * Usage:\n *    `redback.createSortedSet(key);`\n *\n * Reference:\n *    http://redis.io/topics/data-types#sorted-sets\n *\n * Redis Structure:\n *    `(namespace:)key = zset(score => element)`\n */\n\nvar SortedSet = exports.SortedSet = Structure.new();\n\n/**\n * Add one or more elements to the set.\n *\n * To add a single element and score:\n *    `set.add(12, 'foo', callback);`\n *\n * To add multiple elements/scores:\n *    `set.add({foo:12, bar:3}, callback);`\n *\n * @param {int} score (optional)\n * @param {string|Object} element(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSortedSet.prototype.add = function (score, element, callback) {\n    callback = callback || function () {};\n    if (typeof score === 'object') {\n        callback = element;\n        element = score;\n        return this.addAll(element, callback);\n    }\n    this.client.zadd(this.key, score, element, callback);\n    return this;\n}\n\n/**\n * Remove one or more elements from the set.\n *\n * @param {string|Array} element(s)\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSortedSet.prototype.remove = function (element, callback) {\n    callback = callback || function () {};\n    if (Array.isArray(element)) {\n        return this.removeAll(element, callback);\n    }\n    this.client.zrem(this.key, element, callback);\n    return this;\n}\n\n/**\n * Get the number of elements in the set.\n *\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.length = function (callback) {\n    this.client.zcard(this.key, callback);\n    return this;\n}\n\n/**\n * Check whether an element exists in the set.\n *\n * @param {string} element\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.exists =\nSortedSet.prototype.contains = function (element, callback) {\n    this.client.zscore(this.key, element, function (err, score) {\n        callback(err, score != null);\n    });\n    return this;\n}\n\n/**\n * Get the rank of the specified element.\n *\n * @param {string} element\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.rank = function (element, callback) {\n    this.client.zrank(this.key, element, callback)\n    return this;\n}\n\n/**\n * Get the score of the specified element.\n *\n * @param {string} element\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.score = function (element, callback) {\n    this.client.zscore(this.key, element, callback)\n    return this;\n}\n\n/**\n * Increment the specified element's score.\n *\n * @param {string} element\n * @param {int} amount (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this;\n * @api public\n */\n\nSortedSet.prototype.increment =\nSortedSet.prototype.incrBy = function (element, amount, callback) {\n    callback = callback || function () {};\n    if (typeof amount === 'function') {\n        callback = amount;\n        amount = 1;\n    }\n    this.client.zincrby(this.key, amount, element, callback);\n    return this;\n}\n\n/**\n * Decrement the specified element's score.\n *\n * @param {string} element\n * @param {int} amount (optional - default is 1)\n * @param {Function} callback (optional)\n * @return this;\n * @api public\n */\n\nSortedSet.prototype.decrement =\nSortedSet.prototype.decrBy = function (element, amount, callback) {\n    callback = callback || function () {};\n    if (typeof amount === 'function') {\n        callback = amount;\n        amount = 1;\n    }\n    this.client.zincrby(this.key, -1 * amount, element, callback);\n    return this;\n}\n\n/**\n * Add multiple elements to the set. See `add()`.\n *\n * @param {Object} elements\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nSortedSet.prototype.addAll = function (elements, callback) {\n    var self = this, i,\n        remaining = 0,\n        failed = false,\n        add_count = 0;\n\n    for (i in elements) {\n        remaining++;\n        this.client.zadd(this.key, elements[i], i, function (err, added) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err);\n            } else {\n                if (added) add_count++;\n                if (!--remaining) {\n                    callback(null, add_count);\n                }\n            }\n        });\n    }\n    return this;\n}\n\n/**\n * Remove multiple elements from the set. See `remove()`\n *\n * @param {Array} elements\n * @param {Function} callback\n * @return this\n * @api private\n */\n\nSortedSet.prototype.removeAll = function (elements, callback) {\n    var self = this,\n        remaining = elements.length,\n        failed = false,\n        rem_count = 0;\n\n    elements.forEach(function (element) {\n        self.client.zrem(self.key, element, function (err, added) {\n            if (failed) {\n                return;\n            } else if (err) {\n                failed = true;\n                return callback(err);\n            } else {\n                if (added) rem_count++;\n                if (!--remaining) callback(null, rem_count);\n            }\n        });\n    });\n    return this;\n}\n\n/**\n * Get all elements in the set as an object `{element: score, ...}`.\n * If `without_scores` is true then just an array of elements is returned.\n *\n * @param {bool} without_scores (optional - scores are included by default)\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.get = function (without_scores, callback) {\n    if (typeof without_scores === 'function') {\n        callback = without_scores;\n        this.client.zrange(this.key, 0, -1, 'WITHSCORES', this.parseScores(callback));\n    } else {\n        this.client.zrange(this.key, 0, -1, callback);\n    }\n    return this;\n}\n\n\n/**\n * Return a callback that parses a WITHSCORES result:\n *    `['foo','1','bar','2'] => {foo:1, bar:2}`\n *\n * @param {Function} callback\n * @api private\n */\n\nSortedSet.prototype.parseScores = function (callback) {\n    return function (err, results) {\n        if (err) return callback(err, null);\n        if (!results || results.length < 2) return callback(null, null);\n        var len = results.length, i = 0, ret = {}, key, value;\n        while (true) {\n            key = results[i++];\n            value = results[i++];\n            ret[key] = value;\n            if (i >= len) break;\n        }\n        callback(null, ret);\n    }\n}\n\n/**\n * Get elements with scores between the specified range. Elements are returned\n * as an object `{element: score, ..}` and ordered from highest score to lowest.\n *\n * Note that the `start` and `end` range is inclusive and can be an integer or\n * the constants `redback.INF` to represent infinity, or `redback.NINF` to\n * represent negative infinity. `start` must be <= `end`.\n *\n * @param {int} start\n * @param {int} end\n * @param {int} count (optional) - the maximum number of elements to return\n * @param {int} offset (optional) - if using count, start at this offset\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.getScores = function (start, end, count, offset, callback) {\n    if (null === start) start = '-inf';\n    if (null === end) end = '+inf';\n    if (typeof count === 'function') {\n        callback = count;\n        this.client.zrangebyscore(this.key, start, end,\n            'WITHSCORES', this.parseScores(callback));\n        return this;\n    } else if (typeof offset === 'function') {\n        callback = offset;\n        offset = 0;\n    }\n    this.client.zrangebyscore(this.key, start, end, 'WITHSCORES',\n        'LIMIT', offset, count, this.parseScores(callback));\n    return this;\n}\n\n/**\n * The same as `getScores()` but elements are ordered from lowest score to\n * highest.\n *\n * Note that `end` must be <= `start`.\n *\n * @param {int} start\n * @param {int} end\n * @param {int} count (optional) - the maximum number of elements to return\n * @param {int} offset (optional) - if using count, start at this offset\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.getScoresReverse = function (start, end, count, offset, callback) {\n    if (null === start) start = '+inf';\n    if (null === end) end = '-inf';\n    if (typeof count === 'function') {\n        callback = count;\n        this.client.zrevrangebyscore(this.key, start, end,\n            'WITHSCORES', this.parseScores(callback));\n        return this;\n    } else if (typeof offset === 'function') {\n        callback = offset;\n        offset = 0;\n    }\n    this.client.zrevrangebyscore(this.key, start, end, 'WITHSCORES',\n        'LIMIT', offset, count, this.parseScores(callback));\n    return this;\n}\n\n/**\n * Remove elements with scores between the specified range (inclusive).\n *\n * @param {int} start\n * @param {int} end\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSortedSet.prototype.removeScores = function (start, end, callback) {\n    callback = callback || function () {};\n    if (null === start) start = '-inf';\n    if (null === end) end = '+inf';\n    this.client.zremrangebyscore(this.key, start, end, callback);\n    return this;\n}\n\n/**\n * Count the number of elements with scores between the specified\n * range (inclusive).\n *\n * @param {int} start\n * @param {int} end\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.countScores = function (start, end, callback) {\n    if (null === start) start = '-inf';\n    if (null === end) end = '+inf';\n    this.client.zcount(this.key, start, end, callback);\n    return this;\n}\n\n/**\n * Get elements with ranks between the specified range (inclusive).\n *\n * To get the first 3 elements in the set (with the highest scores):\n *    `set.getRanks(0, 2, callback);`\n *\n * To get the last 3 elements in the set (lowest scores):\n *    `set.getRanks(-3, -1, callback);`\n *\n * @param {int} start\n * @param {int} end\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.getRanks = function (start, end, callback) {\n    if (null === start) start = 0;\n    if (null === end) end = -1;\n    this.client.zrange(this.key, start, end,\n        'WITHSCORES', this.parseScores(callback));\n    return this;\n}\n\n/**\n * The same as `getRanks()` but elements are ordered from lowest score\n * to the highest.\n *\n * Note that start and end have been deliberately switched for consistency.\n *\n * getScoresReverse(arg1, arg2, ..) expects arg1 >= arg2 and so does this\n * method.\n *\n * @param {int} end\n * @param {int} start\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.getRanksReverse = function (end, start, callback) {\n    if (null === start) start = -1;\n    if (null === end) end = 0;\n    this.client.zrevrange(this.key, start, end,\n        'WITHSCORES', this.parseScores(callback));\n    return this;\n}\n\n/**\n * Remove elements with ranks between the specified range (inclusive).\n *\n * @param {int} start\n * @param {int} end\n * @param {Function} callback (optional)\n * @return this\n * @api public\n */\n\nSortedSet.prototype.removeRanks = function (start, end, callback) {\n    callback = callback || function () {};\n    if (null === start) start = -1;\n    if (null === end) end = 0;\n    this.client.zremrangebyrank(this.key, start, end, callback);\n    return this;\n}\n\n/**\n * Get `count` elements with the highest scores.\n *\n * @param {int} count\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.highestScores = function (count, callback) {\n    this.getRanks(-1 * count, -1, callback);\n    return this;\n}\n\n/**\n * Get `count` elements with the lowest scores.\n *\n * @param {int} count\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.lowestScores = function (count, callback) {\n    this.getRanks(0, count - 1, callback);\n    return this;\n}\n\n/**\n * Get the intersection of one or more sets. For more information on weights,\n * aggregate functions, etc. see: http://redis.io/commands/zinterstore\n *\n * @param {int} dest\n * @param {string|Set|Array} set(s)\n * @param {int|Array} weights (optional)\n * @param {string} aggregate (optional) - either SUM, MIN or MAX\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.inter = function (dest, sets, weights, aggregate, callback) {\n    var args = [], self = this;\n    args.push(this.getKey(dest));\n\n    //weights/aggregate are optional\n    if (typeof weights === 'function') {\n        callback = weights;\n        weights = aggregate = false;\n    } else if (typeof aggregate === 'function') {\n        callback = aggregate;\n        aggregate = false;\n    }\n\n    //ZINTERSTORE destination numkeys key [key ...]\n    //    [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]\n    if (Array.isArray(sets)) {\n        args.push(sets.length);\n        sets.forEach(function (set) {\n            args.push(self.getKey(set));\n        });\n    } else {\n        args.push(1, this.getKey(sets));\n    }\n    if (weights) {\n        args.push('WEIGHTS');\n        if (Array.isArray(weights)) {\n            weights.forEach(function (weight) {\n                args.push(weight);\n            });\n        } else {\n            args.push(weights);\n        }\n    }\n    if (aggregate) {\n        args.push('AGGREGATE', aggregate);\n    }\n    args.push(callback);\n    this.client.zinterstore.apply(this.client, args);\n    return this;\n}\n\n/**\n * Get the union of one or more sets. For more information on weights,\n * aggregate functions, etc. see: http://redis.io/commands/zunionstore\n *\n * @param {int} dest\n * @param {string|Set|Array} set(s)\n * @param {int|Array} weights (optional)\n * @param {string} aggregate (optional) - either SUM, MIN or MAX\n * @param {Function} callback\n * @return this\n * @api public\n */\n\nSortedSet.prototype.union = function (dest, sets, weights, aggregate, callback) {\n    var args = [], self = this;\n    args.push(this.getKey(dest));\n\n    //weights/aggregate are optional\n    if (typeof weights === 'function') {\n        callback = weights;\n        weights = aggregate = false;\n    } else if (typeof aggregate === 'function') {\n        callback = aggregate;\n        aggregate = false;\n    }\n\n    //ZUNIONSTORE destination numkeys key [key ...]\n    //    [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]\n    if (Array.isArray(sets)) {\n        args.push(sets.length);\n        sets.forEach(function (set) {\n            args.push(self.getKey(set));\n        });\n    } else {\n        args.push(1, this.getKey(sets));\n    }\n    if (weights) {\n        args.push('WEIGHTS');\n        if (Array.isArray(weights)) {\n            weights.forEach(function (weight) {\n                args.push(weight);\n            });\n        } else {\n            args.push(weights);\n        }\n    }\n    if (aggregate) {\n        args.push('AGGREGATE', aggregate);\n    }\n    args.push(callback);\n    this.client.zunionstore.apply(this.client, args);\n    return this;\n}\n"
  },
  {
    "path": "package.json",
    "content": "{ \"name\"          : \"redback\",\n  \"description\"   : \"A high-level Redis library\",\n  \"version\"       : \"0.5.1\",\n  \"homepage\"      : \"https://github.com/chriso/redback\",\n  \"author\"        : \"Chris O'Hara <cohara87@gmail.com>\",\n  \"main\"          : \"index\",\n  \"scripts\": {\n    \"test\": \"redis-cli -n 11 flushdb && expresso -s test/*.test.js\",\n    \"gen-docs\": \"dox -t Redback -d 'A high-level Redis library' -r https://github.com/chriso/redback lib/**/*.js > docs/api.html\"\n  },\n  \"bugs\": {\n    \"url\": \"http://github.com/chriso/redback/issues\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"http://github.com/chriso/redback.git\"\n  },\n  \"dependencies\": {\n    \"redis\": \"*\"\n  },\n  \"devDependencies\": {\n    \"expresso\": \"*\",\n    \"dox\": \"0.0.5\"\n  },\n  \"contributors\": [\n    { \"name\": \"Sreekanth\", \"github\": \"https://github.com/sreeix\", \"email\": \"sreeix@gmail.com\" }\n  ],\n  \"license\": \"MIT\"\n}\n"
  },
  {
    "path": "test/bitfield.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test bitfield': function () {\n        var bitfield = redback.createBitfield('test_bitfield');\n\n        bitfield.set(3, 1, function (err, prev) {\n            assert.ok(!prev);\n\n            bitfield.get(2, function (err, bit) {\n                assert.ok(!bit);\n            });\n\n            bitfield.get(3, function (err, bit) {\n                assert.ok(bit);\n\n                bitfield.set(3, 0, function (err, prev) {\n                    assert.ok(prev);\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/bloomfilter.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n  'test bloom filter#add#single hash': function () {\n    var bloomfilter = redback.createBloomFilter('test_addstructure_bloom_filter_test', 101, 1);\n    bloomfilter.add('test', function(err){\n      bloomfilter.exists('test', function(err, value){\n        assert.equal(true, value);\n      });\n  \n      bloomfilter.exists('this probably does not exist', function(err, value){\n        assert.equal(false, value);\n      });\n      \n    });\n  },\n  \n  'test bloom filter#add#multiple hashs': function () {\n    var bloomfilter = redback.createBloomFilter('test_addstructure_bloom_filter_hello', 101, 3);\n    bloomfilter.add('hello', function(err){\n      bloomfilter.exists('hello', function(err, value){\n        assert.equal(true, value);\n      });\n      bloomfilter.exists('this probably does not exist', function(err, value){\n        assert.equal(false, value);\n      });\n      \n    });\n  },\n  \n  'test bloom filter#reset': function () {\n    var bloomfilter = redback.createBloomFilter('test_addstructure_bloom_filter_bar', 101, 3);\n    \n    bloomfilter.add('bar', function(err){\n      bloomfilter.add('baz', function(err){\n        bloomfilter.exists('bar', function(err, value){\n          assert.equal(true, value);\n          bloomfilter.reset(function(err){\n            bloomfilter.exists('bar', function(err, val){\n              assert.equal(false, val);\n            });\n\n            bloomfilter.exists('baz', function(err, val){\n              assert.equal(false, val);\n            });\n          });\n        });\n        \n      });\n    });\n  }\n  \n  \n}\n"
  },
  {
    "path": "test/cache.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test cache set/get': function () {\n        var cache = redback.createCache('test_cache');\n\n        cache.set('foo', 'bar', function (err) {\n            cache.get('foo', function (err, value) {\n                assert.equal('bar', value);\n            });\n\n            cache.exists('foo', function (err, exists) {\n                assert.ok(exists);\n            });\n\n            cache.exists('nothere', function (err, exists) {\n                assert.ok(!exists);\n            });\n\n            cache.add('foo', 'barbar', function (err, added) {\n                assert.ok(!added);\n            });\n\n            cache.add('bar', 'foofoo', function (err, added) {\n                assert.ok(added);\n\n                cache.get('bar', function (err, value) {\n                    assert.equal('foofoo', value);\n                });\n\n                cache.get('foo', function (err, value) {\n                    assert.equal('bar', value);\n\n                    cache.getSet('foo', 'a', function (err, value) {\n                        assert.equal('bar', value);\n\n                        cache.get('foo', function (err, value) {\n                            assert.equal('a', value);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test cache multi set/get': function () {\n        var cache = redback.createCache('test_cache_multi'), test_obj = {a:'b',c:'d',e:'f'};\n\n        cache.set(test_obj, function (err) {\n            cache.get(['a','c'], function (err, values) {\n                assert.equal('b', values.a);\n                assert.equal('d', values.c);\n            });\n\n            cache.get(function (err, values) {\n                for (var i in test_obj) {\n                    assert.ok(typeof values[i] !== 'undefined');\n                    assert.equal(test_obj[i], values[i]);\n                }\n            });\n\n            cache.add({a:'a', g:'h'}, function (err) {\n                cache.get('a', function (err, value) {\n                    assert.equal('b', value);\n                });\n\n                cache.get('g', function (err, value) {\n                    //assert.equal('h', value);\n                });\n            });\n        });\n    },\n\n    'test cache increment': function () {\n        var cache = redback.createCache('test_cache_increment');\n\n        cache.set('foo', 1, 1, function (err) {\n            cache.increment('foo', function (err) {\n                cache.get('foo', function (err, value) {\n                    assert.equal(2, value);\n                    cache.increment('foo', 5, function (err) {\n                        cache.get('foo', function (err, value) {\n                            assert.equal(7, value);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test cache decrement': function () {\n        var cache = redback.createCache('test_cache_decrement');\n\n        cache.set('foo', 10, function (err) {\n            cache.decrement('foo', function (err) {\n                cache.get('foo', function (err, value) {\n                    assert.equal(9, value);\n                    cache.decrement('foo', 5, function (err) {\n                        cache.get('foo', function (err, value) {\n                            assert.equal(4, value);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test cache key select': function () {\n        var cache = redback.createCache('test_cache_keys');\n\n        cache.set({foo: 'a', foo2: 'b', foo3: 'c', bar: 'd'}, function (err) {\n            cache.keys(function (err, keys) {\n                assert.equal(4, keys.length);\n                assert.ok(keys.indexOf('foo') !== -1);\n                assert.ok(keys.indexOf('foo2') !== -1);\n                assert.ok(keys.indexOf('foo3') !== -1);\n                assert.ok(keys.indexOf('bar') !== -1);\n            });\n\n            cache.keys('f*', function (err, keys) {\n                assert.equal(3, keys.length);\n                assert.ok(keys.indexOf('foo') !== -1);\n                assert.ok(keys.indexOf('foo2') !== -1);\n                assert.ok(keys.indexOf('foo3') !== -1);\n                assert.ok(keys.indexOf('bar') === -1);\n            });\n\n            cache.keys('b?r', function (err, keys) {\n                assert.equal(1, keys.length);\n                assert.ok(keys.indexOf('foo') === -1);\n                assert.ok(keys.indexOf('bar') !== -1);\n            });\n        });\n    },\n\n    'test cache key flush all': function () {\n        var cache = redback.createCache('test_cache_flush');\n\n        cache.set({foo: 'a', foo2: 'b', foo3: 'c', bar: 'd'}, function (err) {\n\n            cache.flush(function (err) {\n                cache.keys(function (err, keys) {\n                    assert.equal(0, keys.length);\n                });\n            });\n        });\n    },\n\n    'test cache key flush by pattern': function () {\n        var cache = redback.createCache('test_cache_flush_pattern');\n\n        cache.set({foo: 'a', foo2: 'b', foo3: 'c', bar: 'd'}, function (err) {\n\n            cache.flush('f*', function (err) {\n                cache.keys(function (err, keys) {\n                    assert.equal(1, keys.length);\n                    assert.ok(keys.indexOf('foo') === -1);\n                    assert.ok(keys.indexOf('foo2') === -1);\n                    assert.ok(keys.indexOf('foo3') === -1);\n                    assert.ok(keys.indexOf('bar') !== -1);\n                });\n            });\n        });\n    },\n\n/*\n    'test cache expiries': function () {\n        var cache = redback.createCache('test_cache_expiries');\n\n        cache.set({foo: 'a', foo2: 'b', foo3: 'c', bar: 'd'}, function (err) {\n\n            cache.expire('foo', 1, function (err) {\n                cache.ttl('foo', function (err, ttl) {\n                    assert.equal(1, ttl);\n\n                    cache.persist('foo', function (err) {\n                        cache.ttl('foo', function (err, ttl) {\n                            assert.equal(-1, ttl);\n                        });\n                    });\n                });\n            });\n\n            var when = new Date();\n            cache.expireAt('foo2', when, function (err) {\n                cache.ttl('foo2', function (err, ttl) {\n                    assert.equal(1, ttl);\n                });\n            });\n        });\n    }\n*/\n}\n\n"
  },
  {
    "path": "test/cappedlist.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test capped list keeping the latest': function() {\n        var list = redback.createCappedList('test_cappedlist', 3);\n\n        //Only the latest 3 items are kept\n        list.push(['a','b','c','d','e','f'], function (err) {\n            list.values(function (err, values) {\n                assert.equal(3, values.length);\n                assert.equal('d', values.shift());\n                assert.equal('e', values.shift());\n                assert.equal('f', values.shift());\n\n                list.push(['g','h'], function (err) {\n                    list.values(function (err, values) {\n                        assert.equal(3, values.length);\n                        assert.equal('f', values.shift());\n                        assert.equal('g', values.shift());\n                        assert.equal('h', values.shift());\n                    });\n                });\n            });\n        });\n    },\n\n    'test capped list length': function () {\n        var list = redback.createCappedList('test_cappedlist_foo', 3);\n\n        list.push(['a','b','c'], function (err) {\n            for (var i = 0; i < 10; i++) {\n                list.push(i, function (err) {\n                    list.values(function (err, values) {\n                        assert.equal(3, values.length);\n                    });\n                });\n            }\n        });\n    },\n\n    'test capped list insert before': function () {\n        var list = redback.createCappedList('test_cappedlist_insertbefore', 3);\n\n        list.push(['a','b','c'], function (err) {\n            list.insertBefore('a', 'z', function (err) {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n\n                    list.insertBefore('c', 'x', function (err) {\n                        list.values(function (err, values) {\n                            assert.equal(3, values.length);\n                            assert.equal('b', values.shift());\n                            assert.equal('x', values.shift());\n                            assert.equal('c', values.shift());\n                        });\n                    });\n\n                });\n            });\n        });\n    },\n\n    'test capped list insert after': function () {\n        var list = redback.createCappedList('test_cappedlist_insertafter', 3);\n\n        list.push(['a','b','c'], function (err) {\n            list.insertAfter('a', 'z', function (err) {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('z', values.shift());\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n\n                    list.insertAfter('c', 'x', function (err) {\n                        list.values(function (err, values) {\n                            assert.equal(3, values.length);\n                            assert.equal('b', values.shift());\n                            assert.equal('c', values.shift());\n                            assert.equal('x', values.shift());\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test capped list unshift': function () {\n        var list = redback.createCappedList('test_cappedlist_unshift', 3);\n\n        list.unshift(['a','b'], function (err) {\n            list.unshift('c', function (err) {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('c', values.shift());\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n\n                    list.unshift('z', function (err) {\n                        list.values(function (err, values) {\n                            assert.equal(3, values.length);\n                            assert.equal('z', values.shift());\n                            assert.equal('c', values.shift());\n                            assert.equal('a', values.shift());\n                        });\n                    });\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/channel.test.js",
    "content": "var redback = require('./common').createClient(),\n    client2 = require('./common').createClient(),\n    assert = require('assert');\n\n//Close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.quit();\n    client2.client.quit();\n}, 500);\n\nmodule.exports = {\n\n    'test channels': function () {\n        var channel = redback.createChannel('test_channel'), received = false;\n\n        channel.on('message', function (msg) {\n            assert.equal('foo', msg);\n            if (msg != 'foo') {\n                assert.ok(false);\n            }\n            received = true;\n        });\n\n        channel.subscribe(function () {\n            //Bind another client so it doesn't affect the other tests\n            channel.setClient(client2.client);\n            channel.publish('foo', function (err) {\n                assert.ok(true);\n            });\n        });\n\n        setTimeout(function () {\n            channel.unsubscribe(function(){\n                assert.ok(true);\n            });\n            assert.ok(received);\n        }, 200);\n    }\n\n}\n"
  },
  {
    "path": "test/common.js",
    "content": "var redback = require('../');\n\nexports.createClient = function (options) {\n    return redback.createClient('redis://localhost/11', options);\n};\n"
  },
  {
    "path": "test/crc32.test.js",
    "content": "var crc32 = require('../lib/Utils').crc32,\n    assert = require('assert');\n\nmodule.exports = {\n  'test crc32': function () {\n    assert.equal(1938594527, crc32('foo'));\n  },\n\n  'test crc32 for 123456789': function () {\n    assert.equal(873187034, crc32('123456789'));\n  }\n}\n"
  },
  {
    "path": "test/densityset.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test density set': function () {\n        var zset = redback.createDensitySet('test_densityset_add');\n\n        zset.add('foo', function (err, was_new) {\n            assert.ok(was_new);\n\n            zset.length(function (err, length) {\n                assert.equal(1, length);\n            });\n\n            zset.contains('foo', function (err, contains) {\n                assert.ok(contains);\n            });\n\n            zset.contains('nothere', function (err, contains) {\n                assert.ok(!contains);\n            });\n\n            zset.score('foo', function (err, score) {\n                assert.equal(1, score);\n\n                zset.rank('foo', function (err, rank) {\n                    assert.equal(0, rank);\n\n                    zset.add('foo', function (err, was_new) {\n                        assert.ok(was_new);\n\n                        zset.score('foo', function (err, score) {\n                            assert.equal(2, score);\n\n                            zset.remove('foo', function (err) {\n                                zset.score('foo', function (err, score) {\n                                    assert.equal(1, score);\n\n                                    zset.remove('foo', function (err, removed) {\n                                        assert.ok(removed);\n\n                                        zset.score('foo', function (err, score) {\n                                            assert.ok(score == null);\n                                        });\n                                    });\n                                });\n                            });\n                        });\n                    });\n                });\n            });\n\n        });\n    },\n\n    'test density set multi add': function () {\n        var zset = redback.createDensitySet('test_densityset_multi_add');\n\n        zset.add(['foo','foo','foo','bar','bar','foobar'], function (err, added) {\n            assert.equal(6, added);\n\n            zset.score('foo', function (err, score) {\n                assert.equal(3, score);\n            });\n\n            zset.rank('foo', function (err, rank) {\n                assert.equal(2, rank);\n            });\n\n            zset.score('bar', function (err, score) {\n                assert.equal(2, score);\n            });\n\n            zset.rank('bar', function (err, rank) {\n                assert.equal(1, rank);\n            });\n\n            zset.score('foobar', function (err, score) {\n                assert.equal(1, score);\n            });\n\n            zset.rank('foobar', function (err, rank) {\n                assert.equal(0, rank);\n            });\n\n            zset.length(function (err, length) {\n                assert.equal(3, length);\n            });\n        });\n    },\n\n    'test sorted set multi remove': function () {\n        var zset = redback.createDensitySet('test_densityset_multi_remove');\n\n        zset.add(['foo','foo','foo','bar','bar','foobar'], function (err, added) {\n            assert.equal(6, added);\n\n            zset.remove(['foo','bar','foobar'], function (err) {\n                zset.score('foo', function (err, score) {\n                    assert.equal(2, score);\n                });\n\n                zset.rank('foo', function (err, rank) {\n                    assert.equal(1, rank);\n                });\n\n                zset.score('bar', function (err, score) {\n                    assert.equal(1, score);\n                });\n\n                zset.rank('bar', function (err, rank) {\n                    assert.equal(0, rank);\n                });\n\n                zset.score('foobar', function (err, score) {\n                    assert.equal(null, score);\n                });\n\n                zset.rank('foobar', function (err, rank) {\n                    assert.equal(null, rank);\n                });\n\n                zset.length(function (err, length) {\n                    assert.equal(2, length);\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/hash.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test simple hash set/get': function() {\n        var hash = redback.createHash('test_hash');\n\n        //Test simple get/set\n        hash.set('foo', 'bar', function (err) {\n            hash.get('foo', function (err, val) {\n                assert.equal('bar', val);\n            });\n            hash.exists('foo', function (err, exists) {\n                assert.ok(exists);\n            });\n            hash.exists('nonexistent', function (err, exists) {\n                assert.ok(!exists);\n            });\n        });\n    },\n\n    'test multi hash set/get': function() {\n        var hash = redback.createHash('test_hash_multi');\n\n        //Test multi set/get\n        hash.set({a: 'b', c: 'd'}, function (err) {\n            hash.get(['a','c'], function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('b', values.shift());\n                assert.equal('d', values.shift());\n            });\n\n            hash.get(function (err, values) {\n                assert.equal('b', values.a);\n                assert.equal('d', values.c);\n            });\n\n            hash.values(function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('b', values.shift());\n                assert.equal('d', values.shift());\n            });\n\n            hash.keys(function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('a', values.shift());\n                assert.equal('c', values.shift());\n            });\n\n            hash.length(function (err, length) {\n                assert.equal(2, length);\n            });\n        });\n    },\n\n    'test hash aggregate': function() {\n        var hash = redback.createHash('test_hash_aggregate');\n\n        //Test multi set/get\n        hash.set({a: 'b', c: 'd'}, function (err) {\n            hash.values(function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('b', values.shift());\n                assert.equal('d', values.shift());\n            });\n\n            hash.keys(function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('a', values.shift());\n                assert.equal('c', values.shift());\n            });\n\n            hash.length(function (err, length) {\n                assert.equal(2, length);\n            });\n        });\n    },\n\n    'test hash add': function() {\n        var hash = redback.createHash('test_hash_add');\n\n        //Test multi set/get\n        hash.set('foo', 'bar', function (err) {\n            assert.equal(null, err);\n            hash.add('foo', 'foo', function (err) {\n                assert.equal(null, err);\n                hash.get('foo', function (err, foo) {\n                    assert.equal('bar', foo);\n                });\n            });\n        });\n    },\n\n    'test hash add': function() {\n        var hash = redback.createHash('test_hash_add');\n\n        //Test multi set/get\n        hash.set('foo', 'bar', function (err) {\n            assert.equal(null, err);\n\n            //'foo' is already set..\n            hash.add('foo', 'foo', function (err) {\n                assert.equal(null, err);\n                hash.get('foo', function (err, foo) {\n                    assert.equal('bar', foo);\n\n                    //Try deleting a hash key\n                    hash.delete('foo', function (err) {\n                        assert.equal(null, err);\n                        hash.get('foo', function (err, foo) {\n                            assert.equal(null, foo);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test hash increment / decrement': function() {\n        var hash = redback.createHash('test_hash_incrdecr');\n\n        //Test increment\n        hash.set('foo', 1, function (err) {\n            hash.increment('foo', 5, function (err) {\n                assert.equal(null, err);\n                hash.get('foo', function (err, foo) {\n                    assert.equal(6, foo);\n\n                    //The increment amount is optional\n                    hash.increment('foo', function (err) {\n                        assert.equal(null, err);\n                        hash.get('foo', function (err, foo) {\n                            assert.equal(7, foo);\n                        });\n                    });\n                });\n            });\n        });\n\n        //Test decrement\n        hash.set('bar', 10, function (err) {\n            hash.decrement('bar', 5, function (err) {\n                assert.equal(null, err);\n                hash.get('bar', function (err, foo) {\n                    assert.equal(5, foo);\n\n                    //The decrement amount is optional\n                    hash.decrement('bar', function (err) {\n                        assert.equal(null, err);\n                        hash.get('bar', function (err, foo) {\n                            assert.equal(4, foo);\n                        });\n                    });\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/keypair.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test keypair set': function () {\n        var keypair = redback.createKeyPair('test_keypair');\n\n        keypair.add('foo', function (err, id) {\n            assert.equal(1, id);\n            keypair.add('bar', function (err, id) {\n                assert.equal(2, id);\n\n                keypair.add('bar', function (err, id) {\n                    assert.equal(2, id);\n                });\n\n                keypair.length(function (err, length) {\n                    assert.equal(2, length);\n                });\n\n                keypair.get(function (err, pairs) {\n                    assert.equal('foo', pairs[1]);\n                    assert.equal('bar', pairs[2]);\n                });\n\n                keypair.get('bar', function (err, id) {\n                    assert.equal(2, id);\n                });\n\n                keypair.get(['foo','bar'], function (err, ids) {\n                    assert.equal(2, ids.length);\n                    assert.equal(1, ids.shift());\n                    assert.equal(2, ids.shift());\n                });\n\n                keypair.getById(2, function (err, value) {\n                    assert.equal('bar', value);\n                });\n\n                keypair.getById([1, 2], function (err, values) {\n                    assert(Array.isArray(values));\n                    assert.equal(values.length, 2);\n                    assert.equal('foo', values.shift());\n                    assert.equal('bar', values.shift());\n                });\n\n                keypair.get('nothere', function (err, id) {\n                    assert.equal(null, id);\n                });\n\n                keypair.values(function (err, values) {\n                    assert.equal(2, values.length);\n                    assert.equal('foo', values.shift());\n                    assert.equal('bar', values.shift());\n                });\n\n                keypair.ids(function (err, ids) {\n                    assert.equal(2, ids.length);\n                    assert.equal(1, ids.shift());\n                    assert.equal(2, ids.shift());\n                });\n\n                keypair.exists('bar', function (err, exists) {\n                    assert.ok(exists);\n                });\n\n                keypair.exists('nothere', function (err, exists) {\n                    assert.ok(!exists);\n                });\n\n                keypair.idExists(2, function (err, exists) {\n                    assert.ok(exists);\n                });\n\n                keypair.idExists(5, function (err, exists) {\n                    assert.ok(!exists);\n                });\n            });\n        });\n    },\n\n    'test adding multiple values to a keypair': function () {\n        var keypair = redback.createKeyPair('test_keypair_multi');\n\n        keypair.add(['a','b','c','d'], function (err, ids) {\n            assert.equal(1, ids.a);\n            assert.equal(2, ids.b);\n            assert.equal(3, ids.c);\n            assert.equal(4, ids.d);\n\n            keypair.delete('a', function (err) {\n                keypair.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n                    assert.equal('d', values.shift());\n\n                    keypair.deleteById(4, function (err) {\n                        keypair.values(function (err, values) {\n                            assert.equal(2, values.length);\n                            assert.equal('b', values.shift());\n                            assert.equal('c', values.shift());\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test uniqueness of keypair values': function () {\n        var keypair = redback.createKeyPair('test_keypair_unique'),\n            count = 50,\n            returned = 0;\n\n        //This is a test of atomicity - even when pipelining add() calls,\n        //values should **ALWAYS** be unique. Only one 'foo' should be added\n        while (count--) {\n            keypair.add('foo', function () {\n                if (returned++ == count) {\n                    keypair.length(function (err, length) {\n                        assert.equal(1, length);\n                    });\n                }\n            });\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/list.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test list push / pop': function() {\n        var list = redback.createList('test_list_pushpop');\n\n        list.push('foo', function (err) {\n            list.push('bar', function (err) {\n                list.values(function (err, values) {\n                    assert.equal(2, values.length);\n                    assert.equal('foo', values.shift());\n                    assert.equal('bar', values.shift());\n\n                    list.push(['a','b'], function (err) {\n                        list.values(function (err, values) {\n                            assert.equal(4, values.length);\n                            assert.equal('foo', values.shift());\n                            assert.equal('bar', values.shift());\n                            assert.equal('a', values.shift());\n                            assert.equal('b', values.shift());\n\n                            list.pop(function (err, value) {\n                                assert.equal('b', value);\n                                list.length(function (err, length) {\n                                    assert.equal(3, length);\n                                });\n                            });\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test list shift': function() {\n        var list = redback.createList('test_list_shiftunshift');\n\n        list.unshift('foo', function (err) {\n            list.unshift('bar', function (err) {\n                list.values(function (err, values) {\n                    assert.equal(2, values.length);\n                    assert.equal('bar', values.shift());\n                    assert.equal('foo', values.shift());\n\n                    list.unshift(['a','b'], function (err) {\n                        list.values(function (err, values) {\n                            assert.equal(4, values.length);\n                            assert.equal('a', values.shift());\n                            assert.equal('b', values.shift());\n                            assert.equal('bar', values.shift());\n                            assert.equal('foo', values.shift());\n\n                            list.shift(function (err, value) {\n                                assert.equal('a', value);\n                                list.length(function (err, length) {\n                                    assert.equal(3, length);\n                                });\n                            });\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test list range': function () {\n        var list = redback.createList('test_list_range');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.range(2, function (err, values) {\n                assert.equal(3, values.length);\n                assert.equal('c', values.shift());\n                assert.equal('d', values.shift());\n                assert.equal('e', values.shift());\n            });\n\n            list.range(0, 1, function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('a', values.shift());\n                assert.equal('b', values.shift());\n            });\n\n            list.range(-2, function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('d', values.shift());\n                assert.equal('e', values.shift());\n            });\n        });\n    },\n\n    'test list get': function () {\n        var list = redback.createList('test_list_get');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.get(1, function (err, value) {\n                assert.equal('b', value);\n            });\n\n            list.get(-1, function (err, value) {\n                assert.equal('e', value);\n            });\n\n            list.get(0, 2, function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('a', values.shift());\n                assert.equal('b', values.shift());\n            });\n\n            list.get(-2, 2, function (err, values) {\n                assert.equal(2, values.length);\n                assert.equal('d', values.shift());\n                assert.equal('e', values.shift());\n            });\n        });\n    },\n\n    'test list cap - keep latest': function () {\n        var list = redback.createList('test_list_cap_latest');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.cap(3, function () {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('c', values.shift());\n                    assert.equal('d', values.shift());\n                    assert.equal('e', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list cap - keep earliest': function () {\n        var list = redback.createList('test_list_cap_earliest');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.cap(3, true, function () {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list trim': function () {\n        var list = redback.createList('test_list_trim');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.trim(1, 3, function () {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n                    assert.equal('d', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list set': function () {\n        var list = redback.createList('test_list_set');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.set(1, 'foo', function () {\n                list.get(0, 3, function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('foo', values.shift());\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list insert': function () {\n        var list = redback.createList('test_list_insert');\n\n        list.unshift(['a','b','c','d','e'], function () {\n            list.insertAfter('a', 'foo', function (err) {\n                list.get(0, 3, function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('foo', values.shift());\n                    assert.equal('b', values.shift());\n                });\n            });\n\n            list.insertBefore('e', 'foo', function (err) {\n                list.get(-3, 3, function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('d', values.shift());\n                    assert.equal('foo', values.shift());\n                    assert.equal('e', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list remove A': function () {\n        var list = redback.createList('test_list_remove_a');\n\n        list.unshift(['a','b','a','b','c'], function () {\n            list.remove('a', function () {\n                list.values(function (err, values) {\n                    assert.equal(4, values.length);\n                    assert.equal('b', values.shift());\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list remove B': function () {\n        var list = redback.createList('test_list_remove_b');\n\n        list.unshift(['a','b','a','b','c'], function () {\n            list.remove('a', -1, function () {\n                list.values(function (err, values) {\n                    assert.equal(4, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n                    assert.equal('b', values.shift());\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n    'test list remove C': function () {\n        var list = redback.createList('test_list_remove_c');\n\n        list.unshift(['a','b','a','b','c'], function () {\n            list.remove('b', 2, function () {\n                list.values(function (err, values) {\n                    assert.equal(3, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('a', values.shift());\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n    'test popshift': function () {\n        var src = redback.createList('test_list_popshift_a');\n        var dest = redback.createList('test_list_popshift_b');\n\n        src.unshift(['a','b','c'], function () {\n            src.popShift(dest, function () {\n                src.values(function (err, values) {\n                    assert.equal(2, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n                });\n\n                dest.values(function (err, values) {\n                    assert.equal(1, values.length);\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n    'test popshift B': function () {\n        var src = redback.createList('test_list_popshift_c');\n        var dest = redback.createList('test_list_popshift_d');\n\n        src.unshift(['a','b','c'], function () {\n            //popShift can also take the actual key string\n            src.popShift('test_list_popshift_d', function () {\n                src.values(function (err, values) {\n                    assert.equal(2, values.length);\n                    assert.equal('a', values.shift());\n                    assert.equal('b', values.shift());\n                });\n\n                dest.values(function (err, values) {\n                    assert.equal(1, values.length);\n                    assert.equal('c', values.shift());\n                });\n            });\n        });\n    },\n\n/*\n    'test blocking list operations - pop': function () {\n        var list = redback.createList('test_list_blocking_pop'), added = false;\n\n        list.pop(1, function (err, value) {\n            if (!added) return assert.ok(false);\n            assert.equal('foo', value);\n        });\n\n        setTimeout(function () {\n            list.push('foo');\n            added = true;\n        }, 100);\n    },\n\n    'test blocking list operations - shift': function () {\n        var list = redback.createList('test_list_blocking_shift'), added = false;\n\n        list.shift(1, function (err, value) {\n            if (!added) return assert.ok(false);\n            assert.equal('foo', value);\n        });\n\n        setTimeout(function () {\n            list.push('foo');\n            added = true;\n        }, 100);\n    }\n*/\n}\n"
  },
  {
    "path": "test/lock.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n// Flush the DB and close the Redis connection after 2 seconds\nsetTimeout(function () {\n    // Ensure we completed all tests\n    assert.strictEqual(_testsCompleted, Object.keys(module.exports).length);\n    redback.client.quit();\n}, 2000);\n\nvar TEST_LOCK = 'test lock';\n\nvar _testsCompleted = 0;\nvar _complete = function() {\n    _testsCompleted++;\n};\n\nmodule.exports = {\n\n    'test lock cannot be stolen': function() {\n        var key = 'test-lock-cannot-be-stolen';\n        var lock = redback.createLock(TEST_LOCK);\n\n        lock.acquire(key, 1, function(err, token) {\n            assert.ok(!err);\n            assert.ok(token);\n\n            // Ensure we don't get a token the next time we try and acquire\n            lock.acquire(key, 1, function(err, token) {\n                assert.ok(!err);\n                assert.ok(!token);\n                _complete();\n            });\n        });\n    },\n\n    'test lock can be re-acquired after release': function() {\n        var key = 'test-lock-can-be-re-acquired-after-released';\n        var lock = redback.createLock(TEST_LOCK);\n\n        lock.acquire(key, 1, function(err, token) {\n            assert.ok(!err);\n            assert.ok(token);\n\n            lock.release(key, token, function(err, hadLock) {\n                assert.ok(!err);\n                assert.ok(hadLock);\n\n                // Ensure we do get a token the next time we try and acquire\n                lock.acquire(key, 1, function(err, token) {\n                    assert.ok(!err);\n                    assert.ok(token);\n                    _complete();\n                });\n            });\n        });\n    },\n\n    'test lock release indicates when releasing with invalid token': function() {\n        var key = 'test-lock-release-indicates-when-releasing-with-invalid-token';\n        var lock = redback.createLock(TEST_LOCK);\n\n        lock.acquire(key, 1, function(err, token) {\n            assert.ok(!err);\n            assert.ok(token);\n\n            // Ensure that releasing with an invalid token indicates we did not\n            // have the lock\n            lock.release(key, 'not the token', function(err, hadLock) {\n                assert.ok(!err);\n                assert.ok(!hadLock);\n\n                lock.release(key, token, function(err, hadLock) {\n                    assert.ok(!err);\n                    assert.ok(hadLock);\n\n                    // Ensure re-release indicates something is wrong\n                    lock.release(key, token, function(err, hadLock) {\n                        assert.ok(!err);\n                        assert.ok(!hadLock);\n                        _complete();\n                    });\n                });\n            });\n        });\n    },\n\n    'test lock can be re-acquired after expiry': function() {\n        var key = 'test-lock-can-be-re-acquired-after-expiry';\n        var lock = redback.createLock(TEST_LOCK);\n\n        lock.acquire(key, 1, function(err, firstToken) {\n            assert.ok(!err);\n            assert.ok(firstToken);\n\n            setTimeout(function() {\n\n                // Ensure we can acquire the lock again\n                lock.acquire(key, 1, function(err, secondToken) {\n                    assert.ok(!err);\n                    assert.ok(secondToken);\n\n                    // Ensure we cannot release it with the old token\n                    lock.release(key, firstToken, function(err, hadLock) {\n                        assert.ok(!err);\n                        assert.ok(!hadLock);\n\n                        // Ensure we cannot re-acquire since it is still held\n                        // by secondToken\n                        lock.acquire(key, 1, function(err, thirdToken) {\n                            assert.ok(!err);\n                            assert.ok(!thirdToken);\n\n                            // Ensure we can successfully release the lock with\n                            // the `secondToken`\n                            lock.release(key, secondToken, function(err, hadLock) {\n                                assert.ok(!err);\n                                assert.ok(hadLock);\n                                _complete();\n                            });\n                        });\n                    });\n                });\n\n            }, 1250);\n        });\n    },\n\n    'test concurrent locks results in only one acquisition': function() {\n        var key = 'test-concurrent-locks-results-in-only-one-acquisition';\n        var lock = redback.createLock(TEST_LOCK);\n\n        var numAcquired = 0;\n        var numCompleted = 0;\n        var iterations = 10;\n        var acquireComplete = function(err, token) {\n            numCompleted++;\n            if (token) {\n                numAcquired++;\n            }\n\n            if (numCompleted === iterations) {\n                 assert.strictEqual(numAcquired, 1);\n                 _complete();\n            }\n        };\n\n        for (var i = 0; i < iterations; i++) {\n            lock.acquire(key, 1, acquireComplete);\n        }\n    }\n};\n"
  },
  {
    "path": "test/namespace.test.js",
    "content": "var redback = require('./common').createClient({namespace: 'foo'}),\n    assert = require('assert');\n\nmodule.exports = {\n\n    'test namespaces': function() {\n        assert.equal('foo', redback.namespace);\n\n        var channel = redback.createChannel('channel__');\n        assert.equal('foo:channel__', channel.name);\n\n        var cache = redback.createCache('cache__');\n        assert.equal('foo:cache__', cache.namespace);\n\n        var list = redback.createList('list__');\n        assert.equal('foo', list.namespace);\n        assert.equal('foo:bar', list.namespaceKey('bar'));\n\n        redback.client.quit();\n    },\n\n}\n"
  },
  {
    "path": "test/queue.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test lifo queue': function () {\n        var lifo = redback.createQueue('test_lifo_queue');\n\n        lifo.add('foo', function (err) {\n            lifo.add('bar', function (err) {\n                lifo.next(function (err, value) {\n                    assert.equal('bar', value);\n                    lifo.next(function (err, value) {\n                        assert.equal('foo', value);\n                        lifo.next(function (err, value) {\n                            assert.equal(null, value);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test fifo queue': function () {\n        var fifo = redback.createQueue('test_fifo_queue', true);\n\n        fifo.enqueue('foo', function (err) {\n            fifo.enqueue('bar', function (err) {\n                fifo.dequeue(function (err, value) {\n                    assert.equal('foo', value);\n                    fifo.dequeue(function (err, value) {\n                        assert.equal('bar', value);\n                        fifo.dequeue(function (err, value) {\n                            assert.equal(null, value);\n                        });\n                    });\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/set.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test set': function () {\n        var set = redback.createSet('test_set');\n\n        set.add('foo', function (err, added) {\n            assert.ok(added);\n            set.add('bar', function (err, added) {\n                assert.ok(added);\n\n                set.elements(function (err, values) {\n                    assert.equal(2, values.length);\n                    values = values.sort(function (a, b) {\n                        return a > b ? -1 : 1;\n                    });\n                    assert.equal('foo', values.shift());\n                    assert.equal('bar', values.shift());\n                });\n\n                set.add('foo', function (err, added) {\n                    assert.ok(!added);\n                });\n\n                set.exists('foo', function (err, exists) {\n                    assert.ok(exists);\n                });\n\n                set.exists('nothere', function (err, exists) {\n                    assert.ok(!exists);\n                });\n\n                set.remove('nothere', function (err, removed) {\n                    assert.ok(!removed);\n                });\n\n                for (var i = 0; i < 5; i++) {\n                    set.random(function (err, element) {\n                        assert.ok(['foo','bar'].indexOf(element) !== -1);\n                    });\n                }\n\n                set.length(function (err, length) {\n                    assert.equal(2, length);\n                });\n            });\n        });\n    },\n\n    'test multi add/remove': function () {\n        var set = redback.createSet('test_set_multi');\n\n        set.add(['a','b','c','d'], function (err, added) {\n            set.elements(function (err, values) {\n                assert.equal(4, values.length);\n                assert.ok(values.indexOf('a') !== -1);\n                assert.ok(values.indexOf('b') !== -1);\n                assert.ok(values.indexOf('c') !== -1);\n                assert.ok(values.indexOf('d') !== -1);\n\n                set.remove('a', function (err, removed) {\n                    assert.ok(removed);\n\n                    set.elements(function (err, values) {\n                        assert.equal(3, values.length);\n                        assert.ok(values.indexOf('b') !== -1);\n                        assert.ok(values.indexOf('c') !== -1);\n                        assert.ok(values.indexOf('d') !== -1);\n\n                        set.remove(['b','c'], function (err, removed) {\n                            assert.ok(removed);\n\n                            set.elements(function (err, values) {\n                                assert.equal(1, values.length);\n                                assert.equal('d', values[0]);\n                            });\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test popping a set element': function () {\n        var set = redback.createSet('test_set_pop'), values = ['a','b','c'];\n\n        set.add(values, function (err, added) {\n            assert.ok(added);\n\n            set.random(true, function (err, element) {\n                assert.ok(values.indexOf(element) !== -1);\n\n                set.random(true, function (err, element) {\n                    assert.ok(values.indexOf(element) !== -1);\n\n                    set.random(true, function (err, element) {\n                        assert.ok(values.indexOf(element) !== -1);\n\n                        set.random(true, function (err, element) {\n                            assert.ok(!element);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test set move': function () {\n        var src  = redback.createSet('test_set_move_src'),\n            dest = redback.createSet('test_set_move_dest');\n\n        src.add(['a','b','c'], function (err, added) {\n            assert.ok(added);\n\n            src.move(dest, 'a', function (err, moved) {\n                assert.ok(moved);\n\n                src.length(function (err, length) {\n                    assert.equal(2, length);\n                });\n\n                dest.elements(function (err, values) {\n                    assert.equal(1, values.length);\n                    assert.equal('a', values[0]);\n                });\n            });\n        });\n    },\n\n    'test set intersect': function () {\n        var set1 = redback.createSet('test_set_inter1'),\n            set2 = redback.createSet('test_set_inter2'),\n            set3 = redback.createSet('test_set_inter3');\n\n        set1.add(['a','b','c','d'], function (err, added) {\n            assert.ok(added);\n            set2.add(['b','c','d','e'], function (err, added) {\n                assert.ok(added);\n                set3.add(['1','2','3','a','b','c'], function (err, added) {\n                    assert.ok(added);\n\n                    set1.inter(set2, set3, function (err, values) {\n                        assert.equal(2, values.length);\n                        assert.ok(values.indexOf('b') !== -1);\n                        assert.ok(values.indexOf('c') !== -1);\n                    });\n\n                    set1.interStore('test_set_inter_store', set2, set3, function (err, stored) {\n                        assert.ok(stored);\n\n                        redback.createSet('test_set_inter_store').elements(function (err, values) {\n                            assert.equal(2, values.length);\n                            assert.ok(values.indexOf('b') !== -1);\n                            assert.ok(values.indexOf('c') !== -1);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test set union': function () {\n        var set1 = redback.createSet('test_set_union1'),\n            set2 = redback.createSet('test_set_union2'),\n            set3 = redback.createSet('test_set_union3');\n\n        set1.add(['a','b','c'], function (err, added) {\n            assert.ok(added);\n            set2.add(['b','c','d'], function (err, added) {\n                assert.ok(added);\n                set3.add(['1','2','3'], function (err, added) {\n                    assert.ok(added);\n\n                    set1.union(set2, set3, function (err, values) {\n                        assert.equal(7, values.length);\n                        assert.ok(values.indexOf('a') !== -1);\n                        assert.ok(values.indexOf('b') !== -1);\n                        assert.ok(values.indexOf('c') !== -1);\n                        assert.ok(values.indexOf('d') !== -1);\n                        assert.ok(values.indexOf('1') !== -1);\n                        assert.ok(values.indexOf('2') !== -1);\n                        assert.ok(values.indexOf('3') !== -1);\n                    });\n\n                    set1.unionStore('test_set_union_store', set2, set3, function (err, stored) {\n                        assert.ok(stored);\n\n                        redback.createSet('test_set_union_store').elements(function (err, values) {\n                            assert.equal(7, values.length);\n                            assert.ok(values.indexOf('a') !== -1);\n                            assert.ok(values.indexOf('b') !== -1);\n                            assert.ok(values.indexOf('c') !== -1);\n                            assert.ok(values.indexOf('d') !== -1);\n                            assert.ok(values.indexOf('1') !== -1);\n                            assert.ok(values.indexOf('2') !== -1);\n                            assert.ok(values.indexOf('3') !== -1);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test set diff': function () {\n        var set1 = redback.createSet('test_set_diff1'),\n            set2 = redback.createSet('test_set_diff2'),\n            set3 = redback.createSet('test_set_diff3');\n\n        set1.add(['a','b','c','d','e','f'], function (err, added) {\n            assert.ok(added);\n            set2.add(['b','c','d'], function (err, added) {\n                assert.ok(added);\n                set3.add(['c','d','e'], function (err, added) {\n                    assert.ok(added);\n\n                    set1.diff(set2, set3, function (err, values) {\n                        assert.equal(2, values.length);\n                        assert.ok(values.indexOf('a') !== -1);\n                        assert.ok(values.indexOf('f') !== -1);\n                    });\n\n                    set1.diff([set2, set3], function (err, values) {\n                        assert.equal(2, values.length);\n                        assert.ok(values.indexOf('a') !== -1);\n                        assert.ok(values.indexOf('f') !== -1);\n                    });\n\n                    set1.diffStore('test_set_diff_store', set2, set3, function (err, stored) {\n                        assert.ok(stored);\n\n                        redback.createSet('test_set_diff_store').elements(function (err, values) {\n                            assert.equal(2, values.length);\n                            assert.ok(values.indexOf('a') !== -1);\n                            assert.ok(values.indexOf('f') !== -1);\n                        });\n                    });\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/socialgraph.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test social graph': function () {\n        var user1 = redback.createSocialGraph(1, 'test_social_graph'),\n            user2 = redback.createSocialGraph(2, 'test_social_graph'),\n            user3 = redback.createSocialGraph(3, 'test_social_graph');\n\n        user1.follow(user2, user3, function (err) {\n            user3.follow(1, 2, function (err) {\n                user2.follow([1], function (err) {\n\n                    user1.getFollowers(function (err, followers) {\n                        var expected = [2,3], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), followers.shift());\n                    });\n\n                    user1.countFollowers(function (err, count) {\n                        assert.equal(2, count);\n                    });\n\n                    user1.getFollowing(function (err, followers) {\n                        var expected = [2,3], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), followers.shift());\n                    });\n\n                    user1.countFollowing(function (err, count) {\n                        assert.equal(2, count);\n                    });\n\n                    user2.getFollowers(function (err, followers) {\n                        var expected = [1,3], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), followers.shift());\n                    });\n\n                    user2.countFollowers(function (err, count) {\n                        assert.equal(2, count);\n                    });\n\n                    user2.getFollowing(function (err, followers) {\n                        var expected = [1], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), followers.shift());\n                    });\n\n                    user2.countFollowing(function (err, count) {\n                        assert.equal(1, count);\n                    });\n\n                    user3.getFollowers(function (err, followers) {\n                        var expected = [1], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), followers.shift());\n                    });\n\n                    user3.countFollowers(function (err, count) {\n                        assert.equal(1, count);\n                    });\n\n                    user3.getFollowing(function (err, followers) {\n                        var expected = [1,2], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), followers.shift());\n                    });\n\n                    user3.countFollowing(function (err, count) {\n                        assert.equal(2, count);\n                    });\n\n                    user3.hasFollower(1, function (err, has) {\n                        assert.ok(has);\n                    });\n\n                    user3.hasFollower(2, function (err, has) {\n                        assert.ok(!has);\n                    });\n\n                    user3.isFollowing(1, function (err, following) {\n                        assert.ok(following);\n                    });\n\n                    user3.isFollowing(2, function (err, following) {\n                        assert.ok(following);\n                    });\n\n                    user3.isFollowing(4, function (err, following) {\n                        assert.ok(!following);\n                    });\n                });\n            });\n        });\n    },\n\n    'test social graph unfollow': function () {\n        var user1 = redback.createSocialGraph(1, 'test_social_graph_rem'),\n            user2 = redback.createSocialGraph(2, 'test_social_graph_rem'),\n            user3 = redback.createSocialGraph(3, 'test_social_graph_rem');\n\n        user1.follow([2,3,4,5,6,7], function (err) {\n            user3.follow(1, 2, 4, 5, 6, function (err) {\n                user2.follow([1], function (err) {\n                    user2.unfollow(1, function (err) {\n                        user2.getFollowing(function (err, following) {\n                            assert.equal(0, following);\n                        });\n                    });\n\n                    user3.unfollow(4, 5, 6, function (err) {\n                        user3.getFollowing(function (err, following) {\n                            var expected = [1,2], l = expected.length;\n                            while (l--) assert.equal(expected.shift(), following.shift());\n\n                            user1.unfollow([user2, user3, 4, 5], function (err) {\n                                user1.getFollowing(function (err, following) {\n                                    var expected = [6,7], l = expected.length;\n                                    while (l--) assert.equal(expected.shift(), following.shift());\n\n                                    user2.getFollowers(function (err, followers) {\n                                        assert.equal(1, followers.length);\n                                        assert.equal(3, followers[0]);\n                                    });\n                                });\n                            });\n                        });\n                    });\n\n                });\n            });\n        });\n    },\n\n    'test social graph get commong followers/following': function () {\n        var user1 = redback.createSocialGraph(1, 'test_social_graph_common'),\n            user2 = redback.createSocialGraph(2, 'test_social_graph_common'),\n            user3 = redback.createSocialGraph(3, 'test_social_graph_common'),\n            user8 = redback.createSocialGraph(8, 'test_social_graph_common'),\n            user9 = redback.createSocialGraph(9, 'test_social_graph_common');\n\n        user1.follow([2,3,4,5,6,7,8,9,10], function (err) {\n            user2.follow([1,3,5,7,9], function (err) {\n                user3.follow([2,5,6,7,8], function (err) {\n\n                    user1.getCommonFollowing(user2, function (err, common) {\n                        var expected = [3,5,7], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), common.shift());\n                    });\n\n                    user1.getCommonFollowing([user2, 3], function (err, common) {\n                        var expected = [5,7], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), common.shift());\n                    });\n\n                    user1.getCommonFollowers(9, function (err, common) {\n                        var expected = [2], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), common.shift());\n                    });\n\n                    user2.getDifferentFollowing(user3, function (err, diff) {\n                        var expected = [1,3], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), diff.shift());\n                    });\n\n                    user2.getDifferentFollowers(9, function (err, diff) {\n                        var expected = [3], l = expected.length;\n                        while (l--) assert.equal(expected.shift(), diff.shift());\n                    });\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/sortedset.test.js",
    "content": "var redback = require('./common').createClient(),\n    assert = require('assert');\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nmodule.exports = {\n\n    'test sorted set': function () {\n        var zset = redback.createSortedSet('test_zset_add');\n\n        zset.add(12, 'foo', function (err, was_new) {\n            assert.ok(was_new);\n\n            zset.length(function (err, length) {\n                assert.equal(1, length);\n            });\n\n            zset.contains('foo', function (err, contains) {\n                assert.ok(contains);\n            });\n\n            zset.contains('nothere', function (err, contains) {\n                assert.ok(!contains);\n            });\n\n            zset.score('foo', function (err, score) {\n                assert.equal(12, score);\n\n                zset.rank('foo', function (err, rank) {\n                    assert.equal(0, rank);\n\n                    zset.add(3, 'foo', function (err, was_new) {\n                        assert.ok(!was_new);\n\n                        zset.score('foo', function (err, score) {\n                            assert.equal(3, score);\n\n                            zset.remove('foo', function (err, removed) {\n                                assert.ok(removed);\n\n                                zset.score('foo', function (err, score) {\n                                    assert.ok(score == null);\n                                });\n\n                                zset.rank('foo', function (err, rank) {\n                                    assert.ok(rank == null);\n                                });\n                            });\n                        });\n                    });\n                });\n            });\n\n        });\n    },\n\n    'test sorted set multi add': function () {\n        var zset = redback.createSortedSet('test_zset_multi_add');\n\n        zset.add({foo:1, bar:2, foobar:3}, function (err) {\n            zset.score('foo', function (err, score) {\n                assert.equal(1, score);\n            });\n\n            zset.rank('foo', function (err, rank) {\n                assert.equal(0, rank);\n            });\n\n            zset.score('bar', function (err, score) {\n                assert.equal(2, score);\n            });\n\n            zset.rank('bar', function (err, rank) {\n                assert.equal(1, rank);\n            });\n\n            zset.score('foobar', function (err, score) {\n                assert.equal(3, score);\n            });\n\n            zset.rank('foobar', function (err, rank) {\n                assert.equal(2, rank);\n            });\n\n            zset.length(function (err, length) {\n                assert.equal(3, length);\n            });\n        });\n    },\n\n    'test sorted set multi remove': function () {\n        var zset = redback.createSortedSet('test_zset_multi_remove');\n\n        zset.add({foo:1, bar:2, foobar:3}, function (err, added) {\n            assert.equal(3, added);\n\n            zset.remove(['foo','bar'], function (err) {\n                zset.score('foo', function (err, score) {\n                    assert.ok(score == null);\n                });\n\n                zset.rank('foo', function (err, rank) {\n                    assert.ok(rank == null);\n                });\n\n                zset.score('bar', function (err, score) {\n                    assert.ok(score == null);\n                });\n\n                zset.rank('bar', function (err, rank) {\n                    assert.ok(rank == null);\n                });\n\n                zset.score('foobar', function (err, score) {\n                    assert.equal(3, score);\n                });\n\n                zset.rank('foobar', function (err, rank) {\n                    assert.equal(0, rank);\n                });\n\n                zset.length(function (err, length) {\n                    assert.equal(1, length);\n                });\n            });\n        });\n    },\n\n    'test sorted set increment decrement': function () {\n        var zset = redback.createSortedSet('test_zset_incdec');\n\n        zset.add({foo:1, bar:2, foobar:3, barfoo: 4}, function (err) {\n            zset.increment('foo', function (err) {\n                zset.score('foo', function (err, score) {\n                    assert.equal(2, score);\n                });\n            });\n            zset.increment('bar', 7, function (err) {\n                zset.score('bar', function (err, score) {\n                    assert.equal(9, score);\n                });\n            });\n            zset.decrement('foobar', function (err) {\n                zset.score('foobar', function (err, score) {\n                    assert.equal(2, score);\n                });\n            });\n            zset.decrement('barfoo', 2, function (err) {\n                zset.score('barfoo', function (err, score) {\n                    assert.equal(2, score);\n                });\n            });\n        });\n    },\n\n    'test sorted set get scores / ranks': function () {\n        var zset = redback.createSortedSet('test_zset_scores');\n\n        zset.add({foo:1, bar:2, foobar:3}, function (err) {\n            zset.get(function (err, set) {\n                var expected = ['foo','bar','foobar'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(3, set.foobar);\n                assert.equal(2, set.bar);\n                assert.equal(1, set.foo);\n            });\n\n            zset.get(true, function (err, set) {\n                var expected = ['foo','bar','foobar'], i, l = 3;\n                while (--l) {\n                    assert.equal(expected.shift(), set.shift());\n                }\n            });\n\n            zset.getScores(redback.NINF, 2, function (err, set) {\n                var expected = ['foo','bar'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(1, set.foo);\n                assert.equal(2, set.bar);\n            });\n\n            zset.getScores(null, 2, 1, function (err, set) {\n                for (var i in set) {\n                    assert.equal('foo', i);\n                }\n                assert.equal(1, set.foo);\n            });\n\n            zset.getScores(null, 2, 1, 1, function (err, set) {\n                for (var i in set) {\n                    assert.equal('bar', i);\n                }\n                assert.equal(2, set.bar);\n            });\n\n            zset.getScoresReverse(2, null, 1, function (err, set) {\n                for (var i in set) {\n                    assert.equal('bar', i);\n                }\n                assert.equal(2, set.bar);\n            });\n\n            zset.getScoresReverse(2, null, 1, 1, function (err, set) {\n                for (var i in set) {\n                    assert.equal('foo', i);\n                }\n                assert.equal(1, set.foo);\n            });\n\n            zset.getScoresReverse(2, redback.NINF, function (err, set) {\n                var expected = ['bar','foo'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(1, set.foo);\n                assert.equal(2, set.bar);\n            });\n\n            zset.getScoresReverse(3, 2, function (err, set) {\n                var expected = ['foobar','bar'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(3, set.foobar);\n                assert.equal(2, set.bar);\n            });\n\n            zset.countScores(1, 3, function (err, count) {\n                assert.equal(3, count);\n            });\n\n            zset.countScores(5, null, function (err, count) {\n                assert.equal(0, count);\n            });\n\n            zset.getScores(2, 3, function (err, set) {\n                var expected = ['bar','foobar'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(3, set.foobar);\n                assert.equal(2, set.bar);\n            });\n\n            zset.getRanks(0, 1, function (err, set) {\n                var expected = ['foo','bar'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(2, set.bar);\n                assert.equal(1, set.foo);\n            });\n\n            zset.getRanksReverse(2, 0, function (err, set) {\n                var expected = ['foobar','bar','foo'], i;\n                for (i in set) {\n                    assert.equal(expected.shift(), i);\n                }\n                assert.equal(3, set.foobar);\n                assert.equal(2, set.bar);\n                assert.equal(1, set.foo);\n            });\n        });\n    },\n\n    'test sorted set remove by score and rank': function () {\n        var zset = redback.createSortedSet('test_zset_remove');\n\n        zset.add({a:1,b:2,c:3,d:4,e:5,f:6,g:7,h:8,i:9}, function (err) {\n            zset.get(true, function (err, values) {\n                var expected = ['a','b','c','d','e','f','g','h','i'];\n                for (var i = 0, l = expected.length; i < l; i++) {\n                    assert.equal(expected.shift(), values.shift());\n                }\n\n                zset.removeScores(1, 3, function (err) {\n                    zset.get(true, function (err, values) {\n                        var expected = ['d','e','f','g','h','i'];\n                        for (var i = 0, l = expected.length; i < l; i++) {\n                            assert.equal(expected.shift(), values.shift());\n                        }\n\n                        zset.removeRanks(-3, -1, function (err) {\n                            zset.get(true, function (err, values) {\n                                var expected = ['d','e','f'];\n                                for (var i = 0, l = expected.length; i < l; i++) {\n                                    assert.equal(expected.shift(), values.shift());\n                                }\n\n                                zset.highestScores(2, function (err, set) {\n                                    var expected = ['e','f'], i;\n                                    for (i in set) {\n                                        assert.equal(expected.shift(), i);\n                                    }\n                                    assert.equal(5, set.e);\n                                    assert.equal(6, set.f);\n                                });\n\n                                zset.lowestScores(2, function (err, set) {\n                                    var expected = ['d','e'], i;\n                                    for (i in set) {\n                                        assert.equal(expected.shift(), i);\n                                    }\n                                    assert.equal(4, set.d);\n                                    assert.equal(5, set.e);\n                                });\n                            });\n                        });\n                    });\n                });\n            });\n        });\n    }\n\n}\n"
  },
  {
    "path": "test/structure.test.js",
    "content": "var redback = require('../'),\n    assert = require('assert'),\n    Structure = redback.Structure,\n    Hash = redback.Hash,\n    List = redback.List;\n\nredback = require('./common').createClient(),\n\n//Flush the DB and close the Redis connection after 500ms\nsetTimeout(function () {\n    redback.client.flushdb(function (err) {\n        redback.client.quit();\n    });\n}, 500);\n\nvar hash = new Hash(null, 'hash'), list = new List(null, 'list'), structure = new Structure(null, 'structure');\n\nmodule.exports = {\n\n    'test structure prototypal inheritance': function() {\n        assert.ok(typeof structure.ttl === 'function');\n\n        //These methods are inherited from Structure\n        assert.ok(typeof hash.ttl === 'function');\n        assert.ok(typeof list.ttl === 'function');\n    },\n\n    'test modifying the base prototype': function () {\n        assert.ok(typeof structure.foo === 'undefined');\n        assert.ok(typeof list.foo === 'undefined');\n        assert.ok(typeof list.foo === 'undefined');\n\n        //All structures inherit from Structure\n        Structure.prototype.foo = function() {\n            return 'foo';\n        };\n\n        //..so all children will inherit its methods\n        assert.equal('foo', hash.foo());\n        assert.equal('foo', list.foo());\n    },\n\n    'test modifying a childs prototype': function () {\n        assert.ok(typeof structure.bar === 'undefined');\n        assert.ok(typeof list.bar === 'undefined');\n        assert.ok(typeof hash.bar === 'undefined');\n\n        //Adding to a structure's prototype should not affect other structures\n        Hash.prototype.bar = function() {\n            return 'bar';\n        }\n\n        assert.equal('bar', hash.bar());\n        assert.ok(typeof structure.bar === 'undefined');\n        assert.ok(typeof list.bar === 'undefined');\n    },\n\n    'test creating a structure with no key': function () {\n        var structures = [\n            'List','Hash','Set','SortedSet','CappedList','DensitySet',\n            'Channel','KeyPair','SocialGraph'\n        ];\n\n        structures.forEach(function (structure) {\n            assert.throws(function () {\n                redback['create' + structure]();\n            });\n        });\n\n        //Cache doesn't require a key..\n        redback.createCache();\n    },\n\n    'test adding a custom structure': function () {\n        redback.addStructure('TestQueue', {\n            init: function (is_fifo) {\n                this.fifo = is_fifo;\n            },\n            add: function (value, callback) {\n                this.client.lpush(this.key, value, callback);\n            },\n            next: function (callback) {\n                var method = this.fifo ? 'rpop' : 'lpop';\n                this.client[method](this.key, callback);\n            }\n        });\n\n        var lifo = redback.createTestQueue('test_addstructure_lifo_queue');\n\n        lifo.add('foo', function (err) {\n            lifo.add('bar', function (err) {\n                lifo.next(function (err, value) {\n                    assert.equal('bar', value);\n                    lifo.next(function (err, value) {\n                        assert.equal('foo', value);\n                        lifo.next(function (err, value) {\n                            assert.equal(null, value);\n                        });\n                    });\n                });\n            });\n        });\n\n        var fifo = redback.createTestQueue('test_addstructure_fifo_queue', true);\n\n        fifo.add('foo', function (err) {\n            fifo.add('bar', function (err) {\n                fifo.next(function (err, value) {\n                    assert.equal('foo', value);\n                    fifo.next(function (err, value) {\n                        assert.equal('bar', value);\n                        fifo.next(function (err, value) {\n                            assert.equal(null, value);\n                        });\n                    });\n                });\n            });\n        });\n    },\n\n    'test structure (bg)save and destroy': function () {\n        var hash = redback.createHash('test_structure_destroy');\n\n        redback.save(function (err) {\n            assert.ok(!err);\n        });\n        redback.save(true, function (err) {\n            assert.ok(!err);\n        });\n\n        hash.set('foo', 'bar', function (err) {\n            hash.get('foo', function (err, value) {\n                assert.equal('bar', value);\n                hash.destroy(function (err) {\n                    hash.get('foo', function (err, value) {\n                        assert.equal(null, value);\n                    });\n                });\n            });\n        });\n    },\n\n    'test an array key': function () {\n        var hash = redback.createHash(['user', 1]);\n        assert.equal('user:1', hash.key);\n    },\n\n    'test get type': function () {\n        var hash = redback.createHash('test_get_type');\n\n        hash.type(function (err, type) {\n            assert.equal('none', type);\n            hash.set('foo', 'bar', function (err) {\n                hash.type(function (err, type) {\n                    assert.equal('hash', type);\n                });\n            });\n        });\n    },\n\n    'test renaming a structure': function () {\n        var hash = redback.createHash('test_rename_hash1'),\n            hash2 = redback.createHash('test_rename_hash2');\n\n        hash.set('foo', 'bar', function (err) {\n            hash.rename('test_rename_hash2', function (err) {\n                hash2.get('foo', function (err, value) {\n                    assert.equal('bar', value);\n                });\n            });\n        });\n    }\n\n/*\n    'test structure expiries': function () {\n        var hash = redback.createHash('test_structure_expiry');\n        hash.expire(1, function (err) {\n            hash.ttl(function (err, ttl) {\n                assert.equal(1, ttl);\n\n                hash.persist(function (err) {\n                    hash.ttl(function (err, ttl) {\n                        assert.equal(-1, ttl);\n                    });\n                });\n            });\n        });\n\n        var set = redback.createSet('test_structure_expiry2');\n        var when = new Date();\n        set.expireAt(when, function (err) {\n            set.ttl(function (err, ttl) {\n                assert.equal(1, ttl);\n            });\n        });\n    }\n*/\n}\n"
  }
]