[
  {
    "path": ".gitignore",
    "content": "/build\n.lock-wscript\ntmp\nnode_modules\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"deps/hiredis\"]\n\tpath = deps/hiredis\n\turl = git://github.com/redis/hiredis.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: node_js\nsudo: false\nenv:\n  - CXX=g++-4.8\naddons:\n  apt:\n    sources:\n    - ubuntu-toolchain-r-test\n    packages:\n    - g++-4.8\n\n\nbefore_install:\n  - node --version | grep -q 'v0.8' && npm install -g npm@2 || true\n\nnode_js:\n  - \"6\"\n  - \"5\"\n  - \"4\"\n  - \"0.12\"\n  - \"0.10\"\n\nnotifications:\n  email: false\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "### 0.5.0 (2016-04-xy)\n\n* Dropping support for EOL Node versions.\n    * This does not mean it breaks right now, but we're not testing against v0.8 and iojs anymore.\n* Do not cast a potentially non-String value to String (#117, iamstolis)\n* Upgrade to new nan version (#119, nicolashenry), avoiding deprecation warnings in Node v6\n\n### 0.4.1 (2015-08-22)\n\n* Upgrade to latest nan to be compatible with io.js (Thanks, Benjamin Byholm)\n\n### 0.4.0 (2015-05-25)\n\n* Upgrade to latest nan to be compatible with io.js\n* Update license attribute\n\n### 0.3.0 (2015-04-03)\n\n* Update to latest hiredis including basic windows support\n* Refactor to use only the parser from hiredis source.\n\n### 0.2.0 (2015-02-08)\n\n* Update to use new hiredis 0.12\n* Update nan to latest version to get io.js support for free (thanks @jonathanong)\n* Bufferify writeCommand, to support unicode and non-string arguments and make it even faster (thanks @stephank)\n* Remove support for Node 0.6\n"
  },
  {
    "path": "COPYING",
    "content": "Copyright (c) 2010-2012, Pieter Noordhuis\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice,\n  this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright notice,\n  this list of conditions and the following disclaimer in the documentation\n  and/or other materials provided with the distribution.\n\n* Neither the name of Redis nor the names of its contributors may be used to\n  endorse or promote products derived from this software without specific prior\n  written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\nANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\nWARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR\nANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES\n(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\nLOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON\nANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\nSOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "Makefile",
    "content": "all:\n\tnode-gyp configure build\n\nclean:\n\tnode-gyp clean\n\ntemp:\n\trm -rf tmp/hiredis\n\tmkdir -p tmp/hiredis\n\tcp -r README* COPYING *.js* binding.gyp src deps test tmp/hiredis\n\tcd tmp/hiredis && rm -rf deps/*/.git* deps/*/*.o deps/*/*.a\n\npackage: temp\n\tcd tmp && tar -czvf hiredis.tgz hiredis\n\ncheck:\n\tnpm test\n"
  },
  {
    "path": "README.md",
    "content": "# [Use node-redis](https://github.com/NodeRedis/node_redis)\n\n`hiredis-node` is deprecated, unmaintained and not updated in forever. [Use node-redis](https://github.com/NodeRedis/node_redis).\n\n---\n\n[![Build Status](https://travis-ci.org/redis/hiredis-node.png?branch=master)](https://travis-ci.org/redis/hiredis-node)\n\n# hiredis-node\n\nNode extension that wraps [hiredis][hiredis].\nBecause Node is already good at doing I/O, hiredis-node only provides\nbindings to the protocol parser.\nThe hiredis protocol parser is faster than JavaScript protocol parsers,\nbut the speedup only becomes noticeable for large replies.\nIf you use Redis for simple SET/GET operations, there won't be a big\nbenefit to using hiredis.\nIf you use Redis for big SUNION/SINTER/LRANGE/ZRANGE operations, the\nbenefit to using hiredis-node can be significant.\n\n[hiredis]: http://github.com/redis/hiredis\n\n## Install\n\nInstall with [NPM][npm]:\n\n```\nnpm install hiredis\n```\n\nThis requires:\n* `gcc` / `g++` 4.8 or newer.\n* `python` 2.7 or any newer 2.x version. `python` 3.x is not supported.\n\nFor running on Travis check the bundled [.travis.yml](.travis.yml).\n\n[npm]: https://npmjs.org/\n\n## Contribute\n\nTo work on the code, first fetch the bundled hiredis submodule, then build hiredis and run the tests.\n\n```\ngit submodule update --init\nnpm install\nnpm test\n```\n\n## Usage\n\nhiredis-node works out of the box with Matt Ranney's [node_redis][node_redis].\nThe latter has an optional dependency on hiredis-node, so maybe you're\nalready using it without knowing.\n\nAlternatively, you can use it directly:\n\n```javascript\nvar hiredis = require(\"hiredis\"),\n    reader = new hiredis.Reader();\n\n// Data comes in\nreader.feed(\"$5\\r\\nhello\\r\\n\");\n\n// Reply comes out\nreader.get() // => \"hello\"\n```\n\nInstead of returning strings for bulk payloads, it can also return\nbuffers:\n\n```javascript\nvar hiredis = require(\"hiredis\"),\n    reader = new hiredis.Reader({ return_buffers: true });\n\n// Data comes in\nreader.feed(\"$5\\r\\nhello\\r\\n\");\n\n// Reply comes out\nreader.get() // => <Buffer 68 65 6c 6c 6f>\n```\n\n[node_redis]: http://github.com/mranney/node_redis\n\n## Windows\n\nSince Version 0.3.0 hiredis-node officially supports Windows.\nA simple `npm install hiredis` should just work.\nIf not, please open a bug report.\n\nThere's also a [Windows fork][windows_fork] by Dmitry Gorbunos (@fuwaneko), which should now be unnecessary.\n\n[windows_fork]: https://github.com/fuwaneko/hiredis-node\n\n## License\n\nThis code is released under the BSD license, after the license of hiredis.\n"
  },
  {
    "path": "appveyor.yml",
    "content": "init:\n    - git config --global core.autocrlf input\n\nenvironment:\n  matrix:\n    - nodejs_version: 6\n    - nodejs_version: 5\n    - nodejs_version: 4\n    - nodejs_version: 0.12\n    - nodejs_version: 0.10\n\nplatform:\n  - x86\n  - x64\n\ninstall:\n  - ps: Install-Product node $env:nodejs_version $env:platform\n  - git submodule update --init --recursive\n  - npm install --msvs_version=2013\n\nbuild: off\n\ntest_script:\n  - node --version\n  - npm --version\n  - \"node test/reader.js\"\n  - \"node test/writer.js\"\n"
  },
  {
    "path": "bench.js",
    "content": "var hiredis = require(\"./hiredis\"),\n    num_clients = 10,\n    active_clients = 0,\n    pipeline = 0,\n    num_requests = parseInt(process.argv[2]) || 20000,\n    issued_requests = 0,\n    test_start;\n\nvar tests = [];\ntests.push({\n    descr: \"PING\",\n    command: [\"PING\"]\n});\ntests.push({\n    descr: \"SET\",\n    command: [\"SET\", \"foo\", \"bar\"]\n});\ntests.push({\n    descr: \"GET\",\n    command: [\"GET\", \"foo\"]\n});\ntests.push({\n    descr: \"LPUSH 8 bytes\",\n    command: [\"LPUSH\", \"mylist-8\", new Buffer(Array(8).join(\"-\"))]\n});\ntests.push({\n    descr: \"LPUSH 64 bytes\",\n    command: [\"LPUSH\", \"mylist-64\", new Buffer(Array(64).join(\"-\"))]\n});\ntests.push({\n    descr: \"LPUSH 512 bytes\",\n    command: [\"LPUSH\", \"mylist-512\", new Buffer(Array(512).join(\"-\"))]\n});\ntests.push({\n    descr: \"LRANGE 10 elements, 8 bytes\",\n    command: [\"LRANGE\", \"mylist-8\", \"0\", \"9\"]\n});\ntests.push({\n    descr: \"LRANGE 100 elements, 8 bytes\",\n    command: [\"LRANGE\", \"mylist-8\", \"0\", \"99\"]\n});\ntests.push({\n    descr: \"LRANGE 100 elements, 64 bytes\",\n    command: [\"LRANGE\", \"mylist-64\", \"0\", \"99\"]\n});\ntests.push({\n    descr: \"LRANGE 100 elements, 512 bytes\",\n    command: [\"LRANGE\", \"mylist-512\", \"0\", \"99\"]\n});\n\nfunction call(client, test) {\n    client.on(\"reply\", function() {\n        if (issued_requests < num_requests) {\n            request();\n        } else {\n            client.end();\n            if (--active_clients == 0)\n                done(test);\n        }\n    });\n\n    function request() {\n        issued_requests++;\n        client.write.apply(client,test.command);\n    };\n\n    request();\n}\n\nfunction done(test) {\n    var time = (new Date - test_start);\n    var op_rate = (num_requests/(time/1000.0)).toFixed(2);\n    console.log(test.descr + \": \" + op_rate + \" ops/sec\");\n    next();\n}\n\nfunction concurrent_test(test) {\n    var i = num_clients;\n    var client;\n\n    issued_requests = 0;\n    test_start = new Date;\n    while(i-- && issued_requests < num_requests) {\n        active_clients++;\n        client = hiredis.createConnection();\n        call(client, test);\n    }\n}\n\nfunction pipelined_test(test) {\n    var client = hiredis.createConnection();\n    var received_replies = 0;\n\n    issued_requests = 0;\n    while (issued_requests < num_requests) {\n        issued_requests++;\n        client.write.apply(client,test.command);\n    }\n\n    test_start = new Date;\n    client.on(\"reply\", function() {\n        if (++received_replies == num_requests) {\n            client.end();\n            done(test);\n        }\n    });\n}\n\nfunction next() {\n    var test = tests.shift();\n    if (test) {\n        if (pipeline) {\n            pipelined_test(test);\n        } else {\n            concurrent_test(test);\n        }\n    }\n}\n\nnext();\n\n"
  },
  {
    "path": "binding.gyp",
    "content": "{\n  'targets': [\n    {\n      'target_name': 'hiredis',\n      'sources': [\n          'src/hiredis.cc'\n        , 'src/reader.cc'\n      ],\n      'include_dirs': [\"<!(node -e \\\"require('nan')\\\")\"],\n      'dependencies': [\n        'deps/hiredis.gyp:hiredis-c'\n      ],\n      'defines': [\n          '_GNU_SOURCE'\n      ],\n      'cflags': [\n          '-Wall',\n          '-O3'\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "deps/hiredis.gyp",
    "content": "{\n  'targets': [\n    {\n      'target_name': 'hiredis-c',\n      'type': 'static_library',\n      'direct_dependent_settings': {\n        'include_dirs': [ '.' ],\n      },\n      'sources': [\n        './hiredis/sds.c',\n        './hiredis/read.c',\n      ],\n      'conditions': [\n        ['OS==\"mac\"', {\n          'xcode_settings': {\n            'GCC_C_LANGUAGE_STANDARD': 'c99'\n          }\n        }],\n        ['OS==\"solaris\"', {\n          'cflags+': [ '-std=c99' ]\n        }]\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "hiredis.js",
    "content": "var net = require(\"net\"),\n    hiredis = require('bindings')('hiredis.node');\n\nvar bufStar = new Buffer(\"*\", \"ascii\");\nvar bufDollar = new Buffer(\"$\", \"ascii\");\nvar bufCrlf = new Buffer(\"\\r\\n\", \"ascii\");\n\nexports.Reader = hiredis.Reader;\n\nexports.writeCommand = function() {\n    var args = arguments,\n        bufLen = new Buffer(String(args.length), \"ascii\"),\n        parts = [bufStar, bufLen, bufCrlf],\n        size = 3 + bufLen.length;\n\n    for (var i = 0; i < args.length; i++) {\n        var arg = args[i];\n        if (!Buffer.isBuffer(arg))\n            arg = new Buffer(String(arg));\n\n        bufLen = new Buffer(String(arg.length), \"ascii\");\n        parts = parts.concat([\n            bufDollar, bufLen, bufCrlf,\n            arg, bufCrlf\n        ]);\n        size += 5 + bufLen.length + arg.length;\n    }\n\n    return Buffer.concat(parts, size);\n}\n\nexports.createConnection = function(port, host) {\n    var s = net.createConnection(port || 6379, host);\n    var r = new hiredis.Reader();\n    var _write = s.write;\n\n    s.write = function() {\n        var data = exports.writeCommand.apply(this, arguments);\n        return _write.call(s, data);\n    }\n\n    s.on(\"data\", function(data) {\n        var reply;\n        r.feed(data);\n        try {\n            while((reply = r.get()) !== undefined)\n                s.emit(\"reply\", reply);\n        } catch(err) {\n            r = null;\n            s.emit(\"error\", err);\n            s.destroy();\n        }\n    });\n\n    return s;\n}\n\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"hiredis\",\n  \"description\": \"Wrapper for reply processing code in hiredis\",\n  \"version\": \"0.5.0\",\n  \"homepage\": \"http://github.com/redis/hiredis-node\",\n  \"author\": \"Jan-Erik Rediger <janerik@fnordig.de>\",\n  \"contributors\": [\n    \"Pieter Noordhuis <pcnoordhuis@gmail.com>\"\n  ],\n  \"main\": \"hiredis\",\n  \"scripts\": {\n    \"test\": \"node test/reader.js && node test/writer.js\"\n  },\n  \"dependencies\": {\n    \"bindings\": \"^1.2.1\",\n    \"nan\": \"^2.3.4\"\n  },\n  \"engines\": {\n    \"node\": \">= 0.10.0\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/redis/hiredis-node.git\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/redis/hiredis-node/issues\"\n  },\n  \"license\": \"BSD-3-Clause\"\n}\n"
  },
  {
    "path": "src/hiredis.cc",
    "content": "#include \"reader.h\"\n\nusing namespace v8;\n\nextern \"C\" {\n    static NAN_MODULE_INIT(init) {\n        hiredis::Reader::Initialize(target);\n    }\n    NODE_MODULE(hiredis, init)\n}\n"
  },
  {
    "path": "src/reader.cc",
    "content": "#include <string.h>\n#include <assert.h>\n#include \"reader.h\"\n\nusing namespace hiredis;\n\nstatic void *tryParentize(const redisReadTask *task, const Local<Value> &v) {\n    Nan::HandleScope scope;\n\n    Reader *r = reinterpret_cast<Reader*>(task->privdata);\n    size_t pidx, vidx;\n\n    if (task->parent != NULL) {\n        pidx = (size_t)task->parent->obj;\n        assert(pidx > 0 && pidx < 9);\n\n        /* When there is a parent, it should be an array. */\n        Local<Value> lvalue = Nan::New(r->handle[pidx]);\n        assert(lvalue->IsArray());\n        Local<Array> larray = lvalue.As<Array>();\n        larray->Set(task->idx,v);\n\n        /* Store the handle when this is an inner array. Otherwise, hiredis\n         * doesn't care about the return value as long as the value is set in\n         * its parent array. */\n        vidx = pidx+1;\n        if (v->IsArray()) {\n            r->handle[vidx].Reset(v);\n            return (void*)vidx;\n        } else {\n            /* Return value doesn't matter for inner value, as long as it is\n             * not NULL (which means OOM for hiredis). */\n            return (void*)0xcafef00d;\n        }\n    } else {\n        /* There is no parent, so this value is the root object. */\n        r->handle[1].Reset(v);\n        return (void*)1;\n    }\n}\n\nstatic void *createArray(const redisReadTask *task, int size) {\n    Nan::HandleScope scope;\n\n    return tryParentize(task, Nan::New<Array>(size));\n}\n\nstatic void *createString(const redisReadTask *task, char *str, size_t len) {\n    Nan::HandleScope scope;\n\n    Reader *r = reinterpret_cast<Reader*>(task->privdata);\n    Local<Value> v(r->createString(str,len));\n\n    if (task->type == REDIS_REPLY_ERROR)\n        v = Exception::Error(v->ToString());\n    return tryParentize(task,v);\n}\n\nstatic void *createInteger(const redisReadTask *task, long long value) {\n    Nan::HandleScope scope;\n    return tryParentize(task, Nan::New<Number>(value));\n}\n\nstatic void *createNil(const redisReadTask *task) {\n    Nan::HandleScope scope;\n    return tryParentize(task, Nan::Null());\n}\n\nstatic redisReplyObjectFunctions v8ReplyFunctions = {\n    createString,\n    createArray,\n    createInteger,\n    createNil,\n    0 /* No free function: cleanup is done in Reader::Get. */\n};\n\nReader::Reader(bool return_buffers) :\n    return_buffers(return_buffers)\n{\n    Nan::HandleScope scope;\n\n    reader = redisReaderCreateWithFunctions(&v8ReplyFunctions);\n    reader->privdata = this;\n\n#if _USE_CUSTOM_BUFFER_POOL\n    if (return_buffers) {\n        Local<Object> global = Context::GetCurrent()->Global();\n        Local<Value> bv = global->Get(String::NewSymbol(\"Buffer\"));\n        assert(bv->IsFunction());\n        Local<Function> bf = Local<Function>::Cast(bv);\n        buffer_fn = Persistent<Function>::New(bf);\n\n        buffer_pool_length = 8*1024; /* Same as node */\n        buffer_pool_offset = 0;\n\n        node::Buffer *b = node::Buffer::New(buffer_pool_length);\n        buffer_pool = Persistent<Object>::New(b->handle_);\n    }\n#endif\n}\n\nReader::~Reader() {\n    redisReaderFree(reader);\n}\n\n/* Don't declare an extra scope here, so the objects are created within the\n * scope inherited from the caller (Reader::Get) and we don't have to the pay\n * the overhead. */\ninline Local<Value> Reader::createString(char *str, size_t len) {\n    if (return_buffers) {\n#if _USE_CUSTOM_BUFFER_POOL\n        if (len > buffer_pool_length) {\n            node::Buffer *b = node::Buffer::New(str,len);\n            return Local<Value>::New(b->handle_);\n        } else {\n            return createBufferFromPool(str,len);\n        }\n#else\n        return Nan::CopyBuffer(str,len).ToLocalChecked();\n#endif\n    } else {\n        return Nan::New<String>(str,len).ToLocalChecked();\n    }\n}\n\n#if _USE_CUSTOM_BUFFER_POOL\nLocal<Value> Reader::createBufferFromPool(char *str, size_t len) {\n    HandleScope scope;\n    Local<Value> argv[3];\n    Local<Object> instance;\n\n    assert(len <= buffer_pool_length);\n    if (buffer_pool_length - buffer_pool_offset < len) {\n        node::Buffer *b = node::Buffer::New(buffer_pool_length);\n        buffer_pool.Dispose();\n        buffer_pool = Persistent<Object>::New(b->handle_);\n        buffer_pool_offset = 0;\n    }\n\n    memcpy(node::Buffer::Data(buffer_pool)+buffer_pool_offset,str,len);\n\n    argv[0] = Local<Value>::New(buffer_pool);\n    argv[1] = Integer::New(len);\n    argv[2] = Integer::New(buffer_pool_offset);\n    instance = buffer_fn->NewInstance(3,argv);\n    buffer_pool_offset += len;\n    return scope.Close(instance);\n}\n#endif\n\nNAN_METHOD(Reader::New) {\n    bool return_buffers = false;\n\n    if (info.Length() > 0 && info[0]->IsObject()) {\n        Local<Value> bv = Nan::Get(info[0].As<Object>(), Nan::New(\"return_buffers\").ToLocalChecked()).ToLocalChecked();\n        if (bv->IsBoolean())\n            return_buffers = Nan::To<bool>(bv).FromJust();\n    }\n\n    Reader *r = new Reader(return_buffers);\n    r->Wrap(info.This());\n    info.GetReturnValue().Set(info.This());\n}\n\nNAN_MODULE_INIT(Reader::Initialize) {\n    Nan::HandleScope scope;\n\n    Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);\n\n    t->InstanceTemplate()->SetInternalFieldCount(1);\n    Nan::SetPrototypeMethod(t, \"feed\", Feed);\n    Nan::SetPrototypeMethod(t, \"get\", Get);\n    Nan::Set(target, Nan::New(\"Reader\").ToLocalChecked(), Nan::GetFunction(t).ToLocalChecked());\n}\n\nNAN_METHOD(Reader::Feed) {\n    Reader *r = Nan::ObjectWrap::Unwrap<Reader>(info.This());\n\n    if (info.Length() == 0) {\n        Nan::ThrowTypeError(\"First argument must be a string or buffer\");\n    } else {\n        if (node::Buffer::HasInstance(info[0])) {\n            Local<Object> buffer_object = info[0].As<Object>();\n            char *data;\n            size_t length;\n\n            data = node::Buffer::Data(buffer_object);\n            length = node::Buffer::Length(buffer_object);\n\n            /* Can't handle OOM for now. */\n            assert(redisReaderFeed(r->reader, data, length) == REDIS_OK);\n        } else if (info[0]->IsString()) {\n            Nan::Utf8String str(info[0].As<String>());\n            redisReplyReaderFeed(r->reader, *str, str.length());\n        } else {\n            Nan::ThrowError(\"Invalid argument\");\n        }\n    }\n\n    info.GetReturnValue().Set(info.This());\n}\n\nNAN_METHOD(Reader::Get) {\n    Reader *r = Nan::ObjectWrap::Unwrap<Reader>(info.This());\n    void *index = NULL;\n    Local<Value> reply;\n    int i;\n\n    if (redisReaderGetReply(r->reader,&index) == REDIS_OK) {\n        if (index == 0) {\n            return;\n        } else {\n            /* Complete replies should always have a root object at index 1. */\n            assert((size_t)index == 1);\n            reply = Nan::New(r->handle[1]);\n\n            /* Dispose and clear used handles. */\n            for (i = 1; i < 3; i++) {\n                r->handle[i].Reset();\n            }\n        }\n    } else {\n        Nan::ThrowError(r->reader->errstr);\n    }\n\n    info.GetReturnValue().Set(reply);\n}\n"
  },
  {
    "path": "src/reader.h",
    "content": "#include <nan.h>\n#include <hiredis/read.h>\n\n#if NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION\n#define _USE_CUSTOM_BUFFER_POOL 1\n#else\n#define _USE_CUSTOM_BUFFER_POOL 0\n#endif\n\nnamespace hiredis {\n\nusing namespace v8;\n\nclass Reader : public Nan::ObjectWrap {\npublic:\n    Reader(bool);\n    ~Reader();\n\n    static NAN_MODULE_INIT(Initialize);\n    static NAN_METHOD(New);\n    static NAN_METHOD(Feed);\n    static NAN_METHOD(Get);\n\n    /* Objects created by the reply object functions need to get back to the\n     * reader when the reply is requested via Reader::Get(). Keep temporary\n     * objects in this handle. Use an array of handles because replies may\n     * include nested multi bulks and child-elements need to be added to the\n     * right respective parent. handle[0] will be unused, so the real index of\n     * an object in this array can be returned from the reply object functions.\n     * The returned value needs to be non-zero to distinguish complete replies\n     * from incomplete replies. These are persistent handles because\n     * Reader::Get might not return a full reply and the objects need to be\n     * kept around for subsequent calls. */\n    Nan::Persistent<Value> handle[9];\n\n    /* Helper function to create string/buffer objects. */\n    Local<Value> createString(char *str, size_t len);\n\nprivate:\n    redisReader *reader;\n\n    /* Determines whether to return strings or buffers for single line and bulk\n     * replies. This defaults to false, so strings are returned by default. */\n    bool return_buffers;\n\n#if _USE_CUSTOM_BUFFER_POOL\n    Local<Value> createBufferFromPool(char *str, size_t len);\n    Persistent<Function> buffer_fn;\n    Persistent<Object> buffer_pool;\n    size_t buffer_pool_length;\n    size_t buffer_pool_offset;\n#endif\n};\n\n};\n\n"
  },
  {
    "path": "test/reader.js",
    "content": "var assert = require(\"assert\"),\n    test = require(\"./testlib\")(),\n    hiredis = require(\"../hiredis\");\n\ntest(\"CreateReader\", function() {\n    var reader = new hiredis.Reader();\n    assert.notEqual(reader, null);\n});\n\ntest(\"StatusReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"+OK\\r\\n\");\n    assert.equal(\"OK\", reader.get());\n});\n\ntest(\"StatusReplyAsBuffer\", function() {\n    var reader = new hiredis.Reader({ return_buffers: true });\n    reader.feed(\"+OK\\r\\n\");\n    var reply = reader.get();\n    assert.ok(Buffer.isBuffer(reply));\n    assert.equal(\"OK\", reply.toString());\n});\n\ntest(\"IntegerReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\":1\\r\\n\");\n    assert.equal(1, reader.get());\n});\n\ntest(\"LargeIntegerReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\":9223372036854775807\\r\\n\");\n    // We test for a different value here, as JavaScript has no 64-bit integers,\n    // only IEEE double precision floating point numbers\n    assert.equal(\"9223372036854776000\", String(reader.get()));\n});\n\ntest(\"ErrorReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"-ERR foo\\r\\n\");\n    var reply = reader.get();\n    assert.equal(Error, reply.constructor);\n    assert.equal(\"ERR foo\", reply.message);\n});\n\ntest(\"ErrorReplyWithReturnBuffers\", function() {\n    var reader = new hiredis.Reader({ return_buffers: true });\n    reader.feed(\"-ERR foo\\r\\n\");\n    var reply = reader.get();\n    assert.equal(Error, reply.constructor);\n    assert.equal(\"ERR foo\", reply.message);\n});\n\ntest(\"NullBulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"$-1\\r\\n\");\n    assert.equal(null, reader.get());\n});\n\ntest(\"EmptyBulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"$0\\r\\n\\r\\n\");\n    assert.equal(\"\", reader.get());\n});\n\ntest(\"BulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"$3\\r\\nfoo\\r\\n\");\n    assert.equal(\"foo\", reader.get());\n});\n\ntest(\"BulkReplyAsBuffer\", function() {\n    var reader = new hiredis.Reader({ return_buffers: true });\n    reader.feed(\"$3\\r\\nfoo\\r\\n\");\n    var reply = reader.get();\n    assert.ok(Buffer.isBuffer(reply));\n    assert.equal(\"foo\", reply.toString());\n});\n\ntest(\"BulkReplyWithEncoding\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"$\" + Buffer.byteLength(\"☃\") + \"\\r\\n☃\\r\\n\");\n    assert.equal(\"☃\", reader.get());\n});\n\ntest(\"NullMultiBulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"*-1\\r\\n\");\n    assert.equal(null, reader.get());\n});\n\ntest(\"EmptyMultiBulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"*0\\r\\n\");\n    assert.deepEqual([], reader.get());\n});\n\ntest(\"MultiBulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"*2\\r\\n$3\\r\\nfoo\\r\\n$3\\r\\nbar\\r\\n\");\n    assert.deepEqual([\"foo\", \"bar\"], reader.get());\n});\n\ntest(\"NestedMultiBulkReply\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"*2\\r\\n*2\\r\\n$3\\r\\nfoo\\r\\n$3\\r\\nbar\\r\\n$3\\r\\nqux\\r\\n\");\n    assert.deepEqual([[\"foo\", \"bar\"], \"qux\"], reader.get());\n});\n\ntest(\"DeeplyNestedMultiBulkReply\", function() {\n    var i;\n    var reader = new hiredis.Reader();\n    var expected = 1;\n\n    for (i = 0; i < 8; i++) {\n      reader.feed(\"*1\\r\\n\");\n      expected = [expected];\n    }\n\n    reader.feed(\":1\\r\\n\");\n\n    assert.deepEqual(reader.get(), expected);\n});\n\ntest(\"TooDeeplyNestedMultiBulkReply\", function() {\n    var i;\n    var reader = new hiredis.Reader();\n\n    for (i = 0; i < 9; i++) {\n      reader.feed(\"*1\\r\\n\");\n    }\n\n    reader.feed(\":1\\r\\n\");\n\n    assert.throws(\n      function() {\n        reader.get();\n      },\n      /nested multi/\n    );\n});\n\ntest(\"MultiBulkReplyWithNonStringValues\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"*3\\r\\n:1\\r\\n+OK\\r\\n$-1\\r\\n\");\n    assert.deepEqual([1, \"OK\", null], reader.get());\n});\n\ntest(\"FeedWithBuffer\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(new Buffer(\"$3\\r\\nfoo\\r\\n\"));\n    assert.deepEqual(\"foo\", reader.get());\n});\n\ntest(\"UndefinedReplyOnIncompleteFeed\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(\"$3\\r\\nfoo\");\n    assert.deepEqual(undefined, reader.get());\n    reader.feed(\"\\r\\n\");\n    assert.deepEqual(\"foo\", reader.get());\n});\n\ntest(\"Leaks\", function() {\n    /* The \"leaks\" utility is only available on OSX. */\n    if (process.platform != \"darwin\") return;\n\n    var done = 0;\n    var leaks = require('child_process').spawn(\"leaks\", [process.pid]);\n    leaks.stdout.on(\"data\", function(data) {\n        var str = data.toString();\n        var notice = \"Node 0.2.5 always leaks 16 bytes (this is \" + process.versions.node + \")\";\n        var matches;\n        if ((matches = /(\\d+) leaks?/i.exec(str)) != null) {\n            if (parseInt(matches[1]) > 0) {\n                console.log(str);\n                console.log('\\x1B[31mNotice: ' + notice + '\\x1B[0m');\n            }\n        }\n        done = 1;\n    });\n\n    process.on('exit', function() {\n        assert.ok(done, \"Leaks test should have completed\");\n    });\n});\n"
  },
  {
    "path": "test/testlib.js",
    "content": "module.exports = function() {\n    function test(str, fn) {\n        try {\n            fn();\n            test.passed++;\n        } catch (err) {\n            console.log(\"\\x1B[1;31m\" + str + \" failed!\\x1B[0m\");\n            console.log(err.stack + \"\\n\");\n            test.failed++;\n        }\n    }\n\n    test.passed = 0;\n    test.failed = 0;\n\n    return test;\n}\n"
  },
  {
    "path": "test/writer.js",
    "content": "var assert = require(\"assert\"),\n    test = require(\"./testlib\")(),\n    hiredis = require(\"../hiredis\");\n\ntest(\"WriteCommand\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(hiredis.writeCommand(\"hello\", \"world\"));\n    assert.deepEqual([\"hello\", \"world\"], reader.get());\n});\n\ntest(\"WriteUnicode\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(hiredis.writeCommand(\"béép\"));\n    assert.deepEqual([\"béép\"], reader.get());\n});\n\ntest(\"WriteBuffer\", function() {\n    var reader = new hiredis.Reader({ return_buffers: true });\n    reader.feed(hiredis.writeCommand(new Buffer([0xC3, 0x28])));\n    var command = reader.get();\n    assert.equal(0xC3, command[0][0]);\n    assert.equal(0x28, command[0][1]);\n});\n\ntest(\"WriteNumber\", function() {\n    var reader = new hiredis.Reader();\n    reader.feed(hiredis.writeCommand(3));\n    assert.deepEqual([\"3\"], reader.get());\n});\n"
  }
]