Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit of greenhouse-notifications NodeJS app.

  • Loading branch information...
commit 745abbf5ce324ae23bef478de596be172f9ff531 0 parents
Jeremy Grelle jeremyg484 authored
Showing with 37,560 additions and 0 deletions.
  1. +11 −0 README
  2. +3 −0  app.js
  3. +9 −0 node_modules/hiredis/.lock-wscript
  4. 0  node_modules/hiredis/README
  5. +121 −0 node_modules/hiredis/bench.js
  6. BIN  node_modules/hiredis/build/.wafpickle-7
  7. +2 −0  node_modules/hiredis/build/c4che/build.config.py
  8. +62 −0 node_modules/hiredis/build/c4che/default.cache.py
  9. +53 −0 node_modules/hiredis/build/config.log
  10. BIN  node_modules/hiredis/build/default/deps/hiredis/hiredis_1.o
  11. BIN  node_modules/hiredis/build/default/deps/hiredis/net_1.o
  12. BIN  node_modules/hiredis/build/default/deps/hiredis/sds_1.o
  13. BIN  node_modules/hiredis/build/default/hiredis.node
  14. BIN  node_modules/hiredis/build/default/hiredis_2.o
  15. BIN  node_modules/hiredis/build/default/libhiredis.a
  16. BIN  node_modules/hiredis/build/default/reader_2.o
  17. +10 −0 node_modules/hiredis/deps/hiredis/COPYING
  18. +112 −0 node_modules/hiredis/deps/hiredis/Makefile
  19. +311 −0 node_modules/hiredis/deps/hiredis/README.md
  20. +2 −0  node_modules/hiredis/deps/hiredis/TODO
  21. +95 −0 node_modules/hiredis/deps/hiredis/adapters/ae.h
  22. +113 −0 node_modules/hiredis/deps/hiredis/adapters/libev.h
  23. +76 −0 node_modules/hiredis/deps/hiredis/adapters/libevent.h
  24. +545 −0 node_modules/hiredis/deps/hiredis/async.c
  25. +126 −0 node_modules/hiredis/deps/hiredis/async.h
  26. +338 −0 node_modules/hiredis/deps/hiredis/dict.c
  27. +126 −0 node_modules/hiredis/deps/hiredis/dict.h
  28. +53 −0 node_modules/hiredis/deps/hiredis/example-ae.c
  29. +47 −0 node_modules/hiredis/deps/hiredis/example-libev.c
  30. +48 −0 node_modules/hiredis/deps/hiredis/example-libevent.c
  31. +68 −0 node_modules/hiredis/deps/hiredis/example.c
  32. +15 −0 node_modules/hiredis/deps/hiredis/fmacros.h
  33. BIN  node_modules/hiredis/deps/hiredis/hiredis-example
  34. BIN  node_modules/hiredis/deps/hiredis/hiredis-test
  35. +1,073 −0 node_modules/hiredis/deps/hiredis/hiredis.c
  36. +184 −0 node_modules/hiredis/deps/hiredis/hiredis.h
  37. +252 −0 node_modules/hiredis/deps/hiredis/net.c
  38. +46 −0 node_modules/hiredis/deps/hiredis/net.h
  39. +604 −0 node_modules/hiredis/deps/hiredis/sds.c
  40. +78 −0 node_modules/hiredis/deps/hiredis/sds.h
  41. +497 −0 node_modules/hiredis/deps/hiredis/test.c
  42. +40 −0 node_modules/hiredis/deps/hiredis/util.h
  43. +14 −0 node_modules/hiredis/hiredis.cc
  44. +34 −0 node_modules/hiredis/hiredis.js
  45. +18 −0 node_modules/hiredis/package.json
  46. +22 −0 node_modules/hiredis/parser_bench.js
  47. +240 −0 node_modules/hiredis/reader.cc
  48. +54 −0 node_modules/hiredis/reader.h
  49. +162 −0 node_modules/hiredis/test/reader.js
  50. +31 −0 node_modules/hiredis/wscript
  51. +568 −0 node_modules/redis/README.md
  52. +125 −0 node_modules/redis/changelog.md
  53. +5 −0 node_modules/redis/examples/auth.js
  54. +24 −0 node_modules/redis/examples/extend.js
  55. +32 −0 node_modules/redis/examples/file.js
  56. +5 −0 node_modules/redis/examples/mget.js
  57. +10 −0 node_modules/redis/examples/monitor.js
  58. +46 −0 node_modules/redis/examples/multi.js
  59. +29 −0 node_modules/redis/examples/multi2.js
  60. +33 −0 node_modules/redis/examples/psubscribe.js
  61. +41 −0 node_modules/redis/examples/pub_sub.js
  62. +17 −0 node_modules/redis/examples/simple.js
  63. +15 −0 node_modules/redis/examples/subqueries.js
  64. +19 −0 node_modules/redis/examples/subquery.js
  65. +29 −0 node_modules/redis/examples/unix_socket.js
  66. +31 −0 node_modules/redis/examples/web_server.js
  67. +761 −0 node_modules/redis/index.js
  68. +41 −0 node_modules/redis/lib/parser/hiredis.js
  69. +302 −0 node_modules/redis/lib/parser/javascript.js
  70. +63 −0 node_modules/redis/lib/queue.js
  71. +6 −0 node_modules/redis/lib/util.js
  72. +131 −0 node_modules/redis/multi_bench.js
  73. +24 −0 node_modules/redis/package.json
  74. +1,116 −0 node_modules/redis/test.js
  75. +58 −0 node_modules/redis/tests/buffer_bench.js
  76. +17 −0 node_modules/redis/tests/test_start_stop.js
  77. +8 −0 node_modules/socket.io/.gitignore
  78. +236 −0 node_modules/socket.io/History.md
  79. +13 −0 node_modules/socket.io/Makefile
  80. +229 −0 node_modules/socket.io/README.md
  81. +61 −0 node_modules/socket.io/example/benchmark.html
  82. +21 −0 node_modules/socket.io/example/cert.crt
  83. +61 −0 node_modules/socket.io/example/chat-ssl.html
  84. +69 −0 node_modules/socket.io/example/chat.html
  85. +18 −0 node_modules/socket.io/example/json.js
  86. +27 −0 node_modules/socket.io/example/key.key
  87. +66 −0 node_modules/socket.io/example/server-ssl.js
  88. +77 −0 node_modules/socket.io/example/server.benchmark.js
  89. +63 −0 node_modules/socket.io/example/server.js
  90. +1 −0  node_modules/socket.io/index.js
  91. +197 −0 node_modules/socket.io/lib/socket.io/client.js
  92. +26 −0 node_modules/socket.io/lib/socket.io/index.js
  93. +166 −0 node_modules/socket.io/lib/socket.io/listener.js
  94. +89 −0 node_modules/socket.io/lib/socket.io/transports/flashsocket.js
  95. +49 −0 node_modules/socket.io/lib/socket.io/transports/htmlfile.js
  96. +35 −0 node_modules/socket.io/lib/socket.io/transports/jsonp-polling.js
  97. +208 −0 node_modules/socket.io/lib/socket.io/transports/websocket.js
  98. +67 −0 node_modules/socket.io/lib/socket.io/transports/xhr-multipart.js
  99. +80 −0 node_modules/socket.io/lib/socket.io/transports/xhr-polling.js
  100. +52 −0 node_modules/socket.io/lib/socket.io/utils.js
  101. +21 −0 node_modules/socket.io/package.json
  102. +3 −0  node_modules/socket.io/support/expresso/.gitignore
  103. +3 −0  node_modules/socket.io/support/expresso/.gitmodules
  104. +128 −0 node_modules/socket.io/support/expresso/History.md
  105. +53 −0 node_modules/socket.io/support/expresso/Makefile
  106. +61 −0 node_modules/socket.io/support/expresso/Readme.md
  107. +856 −0 node_modules/socket.io/support/expresso/bin/expresso
  108. +339 −0 node_modules/socket.io/support/expresso/deps/jscoverage/COPYING
  109. +81 −0 node_modules/socket.io/support/expresso/deps/jscoverage/Makefile.am
  110. +884 −0 node_modules/socket.io/support/expresso/deps/jscoverage/Makefile.in
  111. +8 −0 node_modules/socket.io/support/expresso/deps/jscoverage/Readme.md
  112. +872 −0 node_modules/socket.io/support/expresso/deps/jscoverage/aclocal.m4
  113. +1,526 −0 node_modules/socket.io/support/expresso/deps/jscoverage/config.guess
  114. +92 −0 node_modules/socket.io/support/expresso/deps/jscoverage/config.h.in
  115. +666 −0 node_modules/socket.io/support/expresso/deps/jscoverage/config.rpath
  116. +1,658 −0 node_modules/socket.io/support/expresso/deps/jscoverage/config.sub
  117. +7,971 −0 node_modules/socket.io/support/expresso/deps/jscoverage/configure
  118. +88 −0 node_modules/socket.io/support/expresso/deps/jscoverage/configure.ac
  119. +589 −0 node_modules/socket.io/support/expresso/deps/jscoverage/depcomp
  120. +87 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/demo.html
  121. +45 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/doc.css
  122. +25 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/index.html
  123. +20 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-inverted/script.js
  124. +50 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/jsUnitStyle.css
  125. +10 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/css/readme
  126. +11 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/emptyPage.html
  127. +534 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitCore.js
  128. +81 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitMockTimeout.js
  129. +705 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestManager.js
  130. +44 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTestSuite.js
  131. +102 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitTracer.js
  132. +59 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/jsUnitVersionCheck.js
  133. +12 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-errors.html
  134. +13 −0 ..._modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-failures.html
  135. +13 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts-runs.html
  136. +21 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-counts.html
  137. +189 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-data.html
  138. +23 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-errors.html
  139. +19 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-frame.html
  140. +45 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-loader.html
  141. +25 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-progress.html
  142. +67 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-results.html
  143. +13 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/main-status.html
  144. +16 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainer.html
  145. +77 −0 ...dules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/testContainerController.html
  146. +306 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/app/xbDebug.js
  147. +83 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/css/jsUnitStyle.css
  148. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/green.gif
  149. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/logo_jsunit.gif
  150. BIN  ...modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/powerby-transparent.gif
  151. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/images/red.gif
  152. +56 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/JDOM_license.txt
  153. +213 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/Jetty_license.html
  154. +470 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/MPL-1.1.txt
  155. +340 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/gpl-2.txt
  156. +141 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/index.html
  157. +504 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/lgpl-2.1.txt
  158. +35 −0 ...modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-c.txt
  159. +35 −0 ...ules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/licenses/mpl-tri-license-html.txt
  160. +19 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/readme.txt
  161. +167 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/jsunit/testRunner.html
  162. +7 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/script.js
  163. +25 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example-jsunit/test.html
  164. +24 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example/index.html
  165. +20 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/example/script.js
  166. +164 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/faq.html
  167. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/feed-icon-14x14.png
  168. +45 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/help.html
  169. +151 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/index.html
  170. +25 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/index.html
  171. +38 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-highlight.css
  172. +89 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-ie.css
  173. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage-throbber.gif
  174. +328 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.css
  175. +125 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.html
  176. +1,024 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/jscoverage.js
  177. +65 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented-inverted/script.js
  178. +24 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/index.html
  179. +38 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-highlight.css
  180. +89 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-ie.css
  181. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage-throbber.gif
  182. +328 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.css
  183. +125 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.html
  184. +1,024 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/jscoverage.js
  185. +65 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/instrumented/script.js
  186. +382 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/license.html
  187. +59 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/links.html
  188. +701 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/manual.html
  189. +214 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/news.html
  190. +7 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/reset-fonts-grids.css
  191. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot.png
  192. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot2.png
  193. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot3.png
  194. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot4.png
  195. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot5.png
  196. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot6.png
  197. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/screenshot7.png
  198. +1 −0  node_modules/socket.io/support/expresso/deps/jscoverage/doc/sh_html.min.js
  199. +1 −0  node_modules/socket.io/support/expresso/deps/jscoverage/doc/sh_javascript.min.js
  200. +4 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/sh_main.min.js
  201. +1 −0  node_modules/socket.io/support/expresso/deps/jscoverage/doc/sh_nedit.min.css
  202. BIN  node_modules/socket.io/support/expresso/deps/jscoverage/doc/siliconforks-16x16.png
  203. +138 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/style.css
  204. +58 −0 node_modules/socket.io/support/expresso/deps/jscoverage/doc/users.html
  205. +315 −0 node_modules/socket.io/support/expresso/deps/jscoverage/encoding.c
  206. +33 −0 node_modules/socket.io/support/expresso/deps/jscoverage/encoding.h
  207. +58 −0 node_modules/socket.io/support/expresso/deps/jscoverage/generate-resources.c
  208. +29 −0 node_modules/socket.io/support/expresso/deps/jscoverage/global.h
Sorry, we could not display the entire diff because too many files (868) changed.
11 README
@@ -0,0 +1,11 @@
+This Node application publishes notifications to the main Greenhouse web application. It receives messages from a Redis pub/sub topic and then pushes them out to subscribed browser clients via the Socket.IO Node module.
+
+The app can be started locally (assuming you have NodeJS set up correctly) by executing 'node app.js' from the root directory of the project.
+
+When running in local mode, it is expected that there is also already a local Redis instance running (on localhost using the default Redis port).
+
+When running on Cloud Foundry, it is expected that the app has a Redis service bound to it.
+
+The app will auto-detect its environment on startup, configuring the correct Redis connection based on what is detected.
+
+Socket.IO is currently configured to only use the Comet long-polling technique, as Cloud Foundry does not currently allow WebSocket traffic.
3  app.js
@@ -0,0 +1,3 @@
+//console.log(process.env);
+
+require("./notifications.js");
9 node_modules/hiredis/.lock-wscript
@@ -0,0 +1,9 @@
+argv = ['/usr/local/bin/node-waf', 'configure', 'build']
+blddir = '/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis/build'
+commands = {'dist': 0, 'configure': True, 'distcheck': 0, 'install': 0, 'build': True, 'clean': 0, 'distclean': 0, 'check': 0, 'uninstall': 0}
+cwd = '/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis'
+environ = {'npm_config_onload-script': 'false', 'npm_config_color': 'true', 'npm_config_searchopts': '', 'TERM_PROGRAM_VERSION': '273.1', 'npm_config_group': '20', 'npm_package_homepage': 'http://github.com/pietern/hiredis-node', 'npm_config_browser': 'open', 'npm_config_global': 'false', 'HOME': '/Users/jgrelle', 'DISPLAY': '/tmp/launch-mBLxVX/org.x:0', 'TERM_PROGRAM': 'Apple_Terminal', 'LANG': 'en_US.UTF-8', 'npm_config_pre': 'false', 'SHELL': '/bin/bash', 'npm_config_registry': 'http://registry.npmjs.org/', 'MAVEN_OPTS': '-Xms256m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=256m -Dgpg.passphrase=txba484', '_': '/usr/local/bin/node-waf', 'npm_config_searchexclude': 'null', 'npm_config_loglevel': 'warn', 'npm_config_logfd': '2', 'npm_config_tmp': '/var/folders/3g/3g0uEjaTEb8Q1gku-jZZb++++TI/-Tmp-/', 'npm_package_engines_node': '*', 'npm_config_argv': '"install" "hiredis" "redis" "socket.io"', 'npm_package_scripts_test': 'expresso', 'npm_package_scripts_preinstall': 'node-waf configure build', 'npm_config_tar': 'tar', 'npm_package_main': 'hiredis', 'npm_config_tag': 'latest', 'npm_lifecycle_event': 'preinstall', 'npm_package_version': '0.1.9', 'npm_package_author_email': 'pcnoordhuis@gmail.com', '__CF_USER_TEXT_ENCODING': '0x1F5:0:0', 'npm_config_npaturl': 'http://npat.npmjs.org/', 'npm_config_usage': 'false', 'npm_package_description': 'Wrapper for reply processing code in hiredis', 'npm_config_shell': '/bin/bash', 'npm_config_force': 'false', 'LOGNAME': 'jgrelle', 'npm_config_user': 'nobody', 'npm_config_globalconfig': '/usr/local/etc/npmrc', 'npm_package_name': 'hiredis', 'npm_config_userconfig': '/Users/jgrelle/.npmrc', 'npm_config_unsafe-perm': 'true', 'VERSIONER_PYTHON_PREFER_32_BIT': 'no', 'npm_config_parseable': 'false', 'npm_config_dev': 'false', 'TMPDIR': '/var/folders/3g/3g0uEjaTEb8Q1gku-jZZb++++TI/-Tmp-/', 'npm_config_version': 'false', 'npm_config_username': '', 'USER': 'jgrelle', 'PATH': '/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis/node_modules/.bin:/Users/jgrelle/workspace/greenhouse-notifications/node_modules/.bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/X11/bin:~/android-sdk-mac_x86/tools:~/android-sdk-mac_x86/platform-tools', 'npm_config_gzipbin': 'gzip', 'npm_package_author_name': 'Pieter Noordhuis', 'npm_package_directories_lib': '.', 'TERM': 'xterm-color', 'VERSIONER_PYTHON_VERSION': '2.6', 'SHLVL': '2', 'npm_config_description': 'true', 'npm_config_bindist': '0.4-darwin-10.7.0', 'npm_config_cache': '/Users/jgrelle/.npm', 'npm_config_viewer': 'man', 'npm_config_proxy': 'null', 'npm_config_showlevel': '2', 'npm_config_rebuild-bundle': 'true', 'npm_config_depth': 'Infinity', 'SSH_AUTH_SOCK': '/tmp/launch-wj6hWd/Listeners', 'npm_config_long': 'false', 'Apple_PubSub_Socket_Render': '/tmp/launch-6uNObH/Render', 'npm_config_editor': 'vi', 'ANT_OPTS': '-Xms256m -Xmx1024m -XX:PermSize=128m -XX:MaxPermSize=512m', 'npm_config_prefix': '/usr/local', 'npm_config_npat': 'false', 'npm_config_outfd': '1', 'npm_config_node-version': 'v0.4.5', 'npm_lifecycle_script': 'node-waf configure build', 'PWD': '/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis', 'COMMAND_MODE': 'unix2003'}
+files = []
+hash = 0
+options = {'compile_targets': None, 'force': False, 'verbose': 0, 'nocache': False, 'progress_bar': 0, 'destdir': '', 'keep': False, 'zones': '', 'blddir': '', 'prefix': '/usr/local/', 'jobs': 4, 'srcdir': '', 'check_cxx_compiler': 'g++', 'check_c_compiler': 'gcc'}
+srcdir = '/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis'
0  node_modules/hiredis/README
No changes.
121 node_modules/hiredis/bench.js
@@ -0,0 +1,121 @@
+var hiredis = require("./hiredis"),
+ num_clients = 10,
+ active_clients = 0,
+ pipeline = 0,
+ num_requests = parseInt(process.argv[2]) || 20000,
+ issued_requests = 0,
+ test_start;
+
+var tests = [];
+tests.push({
+ descr: "PING",
+ command: ["PING"]
+});
+tests.push({
+ descr: "SET",
+ command: ["SET", "foo", "bar"]
+});
+tests.push({
+ descr: "GET",
+ command: ["GET", "foo"]
+});
+tests.push({
+ descr: "LPUSH 8 bytes",
+ command: ["LPUSH", "mylist-8", new Buffer(Array(8).join("-"))]
+});
+tests.push({
+ descr: "LPUSH 64 bytes",
+ command: ["LPUSH", "mylist-64", new Buffer(Array(64).join("-"))]
+});
+tests.push({
+ descr: "LPUSH 512 bytes",
+ command: ["LPUSH", "mylist-512", new Buffer(Array(512).join("-"))]
+});
+tests.push({
+ descr: "LRANGE 10 elements, 8 bytes",
+ command: ["LRANGE", "mylist-8", "0", "9"]
+});
+tests.push({
+ descr: "LRANGE 100 elements, 8 bytes",
+ command: ["LRANGE", "mylist-8", "0", "99"]
+});
+tests.push({
+ descr: "LRANGE 100 elements, 64 bytes",
+ command: ["LRANGE", "mylist-64", "0", "99"]
+});
+tests.push({
+ descr: "LRANGE 100 elements, 512 bytes",
+ command: ["LRANGE", "mylist-512", "0", "99"]
+});
+
+function call(client, test) {
+ client.on("reply", function() {
+ if (issued_requests < num_requests) {
+ request();
+ } else {
+ client.end();
+ if (--active_clients == 0)
+ done(test);
+ }
+ });
+
+ function request() {
+ issued_requests++;
+ client.write.apply(client,test.command);
+ };
+
+ request();
+}
+
+function done(test) {
+ var time = (new Date - test_start);
+ var op_rate = (num_requests/(time/1000.0)).toFixed(2);
+ console.log(test.descr + ": " + op_rate + " ops/sec");
+ next();
+}
+
+function concurrent_test(test) {
+ var i = num_clients;
+ var client;
+
+ issued_requests = 0;
+ test_start = new Date;
+ while(i-- && issued_requests < num_requests) {
+ active_clients++;
+ client = hiredis.createConnection();
+ call(client, test);
+ }
+}
+
+function pipelined_test(test) {
+ var client = hiredis.createConnection();
+ var received_replies = 0;
+
+ issued_requests = 0;
+ while (issued_requests < num_requests) {
+ issued_requests++;
+ client.write.apply(client,test.command);
+ }
+
+ test_start = new Date;
+ client.on("reply", function() {
+ if (++received_replies == num_requests) {
+ client.end();
+ done(test);
+ }
+ });
+}
+
+function next() {
+ var test = tests.shift();
+ if (test) {
+ if (pipeline) {
+ pipelined_test(test);
+ } else {
+ concurrent_test(test);
+ }
+ }
+}
+
+next();
+
BIN  node_modules/hiredis/build/.wafpickle-7
Binary file not shown
2  node_modules/hiredis/build/c4che/build.config.py
@@ -0,0 +1,2 @@
+version = 0x105016
+tools = [{'tool': 'ar', 'tooldir': None, 'funs': None}, {'tool': 'cc', 'tooldir': None, 'funs': None}, {'tool': 'gcc', 'tooldir': None, 'funs': None}, {'tool': 'compiler_cc', 'tooldir': None, 'funs': None}, {'tool': 'cxx', 'tooldir': None, 'funs': None}, {'tool': 'gxx', 'tooldir': None, 'funs': None}, {'tool': 'compiler_cxx', 'tooldir': None, 'funs': None}, {'tool': 'osx', 'tooldir': None, 'funs': None}, {'tool': 'node_addon', 'tooldir': None, 'funs': None}]
62 node_modules/hiredis/build/c4che/default.cache.py
@@ -0,0 +1,62 @@
+AR = '/usr/bin/ar'
+ARFLAGS = 'rcs'
+CC = ['/usr/bin/gcc']
+CCDEFINES_ST = '-D%s'
+CCFLAGS = ['-Wall', '-fPIC', '-O3', '-g']
+CCFLAGS_DEBUG = ['-g']
+CCFLAGS_MACBUNDLE = ['-fPIC']
+CCFLAGS_NODE = ['-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64']
+CCFLAGS_RELEASE = ['-O2']
+CCLNK_SRC_F = ''
+CCLNK_TGT_F = ['-o', '']
+CC_NAME = 'gcc'
+CC_SRC_F = ''
+CC_TGT_F = ['-c', '-o', '']
+CC_VERSION = ('4', '2', '1')
+COMPILER_CC = 'gcc'
+COMPILER_CXX = 'g++'
+CPP = '/usr/bin/cpp'
+CPPFLAGS_NODE = ['-D_GNU_SOURCE', '-DEV_MULTIPLICITY=0']
+CPPPATH_NODE = '/usr/local/Cellar/node/0.4.5/include/node'
+CPPPATH_ST = '-I%s'
+CXX = ['/usr/bin/g++']
+CXXDEFINES_ST = '-D%s'
+CXXFLAGS = ['-g', '-Wall', '-O3']
+CXXFLAGS_DEBUG = ['-g']
+CXXFLAGS_NODE = ['-D_LARGEFILE_SOURCE', '-D_FILE_OFFSET_BITS=64']
+CXXFLAGS_RELEASE = ['-O2']
+CXXLNK_SRC_F = ''
+CXXLNK_TGT_F = ['-o', '']
+CXX_NAME = 'gcc'
+CXX_SRC_F = ''
+CXX_TGT_F = ['-c', '-o', '']
+DEST_CPU = 'x86_64'
+DEST_OS = 'darwin'
+FULLSTATIC_MARKER = '-static'
+LIBDIR = '/Users/jgrelle/.node_libraries'
+LIBPATH_HIREDIS = 'default'
+LIBPATH_NODE = '/usr/local/Cellar/node/0.4.5/lib'
+LIBPATH_ST = '-L%s'
+LIB_HIREDIS = 'hiredis'
+LIB_ST = '-l%s'
+LINKFLAGS_MACBUNDLE = ['-bundle', '-undefined', 'dynamic_lookup']
+LINK_CC = ['/usr/bin/gcc']
+LINK_CXX = ['/usr/bin/g++']
+NODE_PATH = '/Users/jgrelle/.node_libraries'
+PREFIX = '/usr/local'
+PREFIX_NODE = '/usr/local/Cellar/node/0.4.5'
+RANLIB = '/usr/bin/ranlib'
+RPATH_ST = '-Wl,-rpath,%s'
+SHLIB_MARKER = ''
+SONAME_ST = ''
+STATICLIBPATH_ST = '-L%s'
+STATICLIB_MARKER = ''
+STATICLIB_ST = '-l%s'
+macbundle_PATTERN = '%s.bundle'
+program_PATTERN = '%s'
+shlib_CCFLAGS = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']
+shlib_CXXFLAGS = ['-fPIC', '-compatibility_version', '1', '-current_version', '1']
+shlib_LINKFLAGS = ['-dynamiclib']
+shlib_PATTERN = 'lib%s.dylib'
+staticlib_LINKFLAGS = []
+staticlib_PATTERN = 'lib%s.a'
53 node_modules/hiredis/build/config.log
@@ -0,0 +1,53 @@
+# project noname (1.0) configured on Mon Apr 11 13:13:49 2011 by
+# waf 1.5.16 (abi 7, python 20601f0 on darwin)
+# using /usr/local/bin/node-waf configure build
+#
+
+----------------------------------------
+Setting srcdir to
+/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis
+
+----------------------------------------
+Setting blddir to
+/Users/jgrelle/workspace/greenhouse-notifications/node_modules/hiredis/build
+
+----------------------------------------
+Checking for program gcc or cc
+ find program=['gcc', 'cc'] paths=[] var='CC'
+ -> '/usr/bin/gcc'
+
+----------------------------------------
+Checking for program cpp
+ find program=['cpp'] paths=[] var='CPP'
+ -> '/usr/bin/cpp'
+
+----------------------------------------
+Checking for program ar
+ find program=['ar'] paths=[] var='AR'
+ -> '/usr/bin/ar'
+
+----------------------------------------
+Checking for program ranlib
+ find program=['ranlib'] paths=[] var='RANLIB'
+ -> '/usr/bin/ranlib'
+
+----------------------------------------
+Checking for gcc
+ok
+
+----------------------------------------
+Checking for program g++ or c++
+ find program=['g++', 'c++'] paths=[] var='CXX'
+ -> '/usr/bin/g++'
+
+----------------------------------------
+Checking for g++
+ok
+
+----------------------------------------
+Checking for node path
+not found
+
+----------------------------------------
+Checking for node prefix
+ok /usr/local/Cellar/node/0.4.5
BIN  node_modules/hiredis/build/default/deps/hiredis/hiredis_1.o
Binary file not shown
BIN  node_modules/hiredis/build/default/deps/hiredis/net_1.o
Binary file not shown
BIN  node_modules/hiredis/build/default/deps/hiredis/sds_1.o
Binary file not shown
BIN  node_modules/hiredis/build/default/hiredis.node
Binary file not shown
BIN  node_modules/hiredis/build/default/hiredis_2.o
Binary file not shown
BIN  node_modules/hiredis/build/default/libhiredis.a
Binary file not shown
BIN  node_modules/hiredis/build/default/reader_2.o
Binary file not shown
10 node_modules/hiredis/deps/hiredis/COPYING
@@ -0,0 +1,10 @@
+Copyright (c) 2006-2009, Salvatore Sanfilippo
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of Redis nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
112 node_modules/hiredis/deps/hiredis/Makefile
@@ -0,0 +1,112 @@
+# Hiredis Makefile
+# Copyright (C) 2010 Salvatore Sanfilippo <antirez at gmail dot com>
+# This file is released under the BSD license, see the COPYING file
+
+OBJ = net.o hiredis.o sds.o async.o
+BINS = hiredis-example hiredis-test
+
+uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
+OPTIMIZATION?=-O3
+ifeq ($(uname_S),SunOS)
+ CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -D__EXTENSIONS__ -D_XPG6 $(ARCH) $(PROF)
+ CCLINK?=-ldl -lnsl -lsocket -lm -lpthread
+ LDFLAGS?=-L. -Wl,-R,.
+ DYLIBNAME?=libhiredis.so
+ DYLIB_MAKE_CMD?=$(CC) -G -o ${DYLIBNAME} ${OBJ}
+ STLIBNAME?=libhiredis.a
+ STLIB_MAKE_CMD?=ar rcs ${STLIBNAME} ${OBJ}
+else ifeq ($(uname_S),Darwin)
+ CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
+ CCLINK?=-lm -pthread
+ LDFLAGS?=-L. -Wl,-rpath,.
+ OBJARCH?=-arch i386 -arch x86_64
+ DYLIBNAME?=libhiredis.dylib
+ DYLIB_MAKE_CMD?=libtool -dynamic -o ${DYLIBNAME} -lm ${DEBUG} - ${OBJ}
+ STLIBNAME?=libhiredis.a
+ STLIB_MAKE_CMD?=libtool -static -o ${STLIBNAME} - ${OBJ}
+else
+ CFLAGS?=-std=c99 -pedantic $(OPTIMIZATION) -fPIC -Wall -W -Wstrict-prototypes -Wwrite-strings $(ARCH) $(PROF)
+ CCLINK?=-lm -pthread
+ LDFLAGS?=-L. -Wl,-rpath,.
+ DYLIBNAME?=libhiredis.so
+ DYLIB_MAKE_CMD?=gcc -shared -Wl,-soname,${DYLIBNAME} -o ${DYLIBNAME} ${OBJ}
+ STLIBNAME?=libhiredis.a
+ STLIB_MAKE_CMD?=ar rcs ${STLIBNAME} ${OBJ}
+endif
+CCOPT= $(CFLAGS) $(CCLINK)
+DEBUG?= -g -ggdb
+
+PREFIX?= /usr/local
+INSTALL_INC= $(PREFIX)/include/hiredis
+INSTALL_LIB= $(PREFIX)/lib
+INSTALL= cp -a
+
+all: ${DYLIBNAME} ${BINS}
+
+# Deps (use make dep to generate this)
+net.o: net.c fmacros.h net.h
+async.o: async.c async.h hiredis.h sds.h util.h dict.c dict.h
+example.o: example.c hiredis.h
+hiredis.o: hiredis.c hiredis.h net.h sds.h util.h
+sds.o: sds.c sds.h
+test.o: test.c hiredis.h
+
+${DYLIBNAME}: ${OBJ}
+ ${DYLIB_MAKE_CMD}
+
+${STLIBNAME}: ${OBJ}
+ ${STLIB_MAKE_CMD}
+
+dynamic: ${DYLIBNAME}
+static: ${STLIBNAME}
+
+# Binaries:
+hiredis-example-libevent: example-libevent.c adapters/libevent.h ${DYLIBNAME}
+ $(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS) -lhiredis -levent example-libevent.c
+
+hiredis-example-libev: example-libev.c adapters/libev.h ${DYLIBNAME}
+ $(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS) -lhiredis -lev example-libev.c
+
+ifndef AE_DIR
+hiredis-example-ae:
+ @echo "Please specify AE_DIR (e.g. <redis repository>/src)"
+ @false
+else
+hiredis-example-ae: example-ae.c adapters/ae.h ${DYLIBNAME}
+ $(CC) -o $@ $(CCOPT) $(DEBUG) -I$(AE_DIR) $(LDFLAGS) -lhiredis example-ae.c $(AE_DIR)/ae.o $(AE_DIR)/zmalloc.o
+endif
+
+hiredis-%: %.o ${DYLIBNAME}
+ $(CC) -o $@ $(CCOPT) $(DEBUG) $(LDFLAGS) -lhiredis $<
+
+test: hiredis-test
+ ./hiredis-test
+
+.c.o:
+ $(CC) -c $(CFLAGS) $(OBJARCH) $(DEBUG) $(COMPILE_TIME) $<
+
+clean:
+ rm -rf ${DYLIBNAME} ${STLIBNAME} $(BINS) hiredis-example* *.o *.gcda *.gcno *.gcov
+
+dep:
+ $(CC) -MM *.c
+
+install: ${DYLIBNAME} ${STLIBNAME}
+ mkdir -p $(INSTALL_INC) $(INSTALL_LIB)
+ $(INSTALL) hiredis.h async.h adapters $(INSTALL_INC)
+ $(INSTALL) ${DYLIBNAME} ${STLIBNAME} $(INSTALL_LIB)
+
+32bit:
+ @echo ""
+ @echo "WARNING: if it fails under Linux you probably need to install libc6-dev-i386"
+ @echo ""
+ $(MAKE) ARCH="-m32"
+
+gprof:
+ $(MAKE) PROF="-pg"
+
+gcov:
+ $(MAKE) PROF="-fprofile-arcs -ftest-coverage"
+
+noopt:
+ $(MAKE) OPTIMIZATION=""
311 node_modules/hiredis/deps/hiredis/README.md
@@ -0,0 +1,311 @@
+# HIREDIS
+
+Hiredis is a minimalistic C client library for the [Redis](http://redis.io/) database.
+
+It is minimalistic because it just adds minimal support for the protocol, but
+at the same time it uses an high level printf-alike API in order to make it
+much higher level than otherwise suggested by its minimal code base and the
+lack of explicit bindings for every Redis command.
+
+Apart from supporting sending commands and receiving replies, it comes with
+a reply parser that is decoupled from the I/O layer. It
+is a stream parser designed for easy reusability, which can for instance be used
+in higher level language bindings for efficient reply parsing.
+
+Hiredis only supports the binary-safe Redis protocol, so you can use it with any
+Redis version >= 1.2.0.
+
+The library comes with multiple APIs. There is the
+*synchronous API*, the *asynchronous API* and the *reply parsing API*.
+
+## UPGRADING
+
+Version 0.9.0 is a major overhaul of hiredis in every aspect. However, upgrading existing
+code using hiredis should not be a big pain. The key thing to keep in mind when
+upgrading is that hiredis >= 0.9.0 uses a `redisContext*` to keep state, in contrast to
+the stateless 0.0.1 that only has a file descriptor to work with.
+
+## Synchronous API
+
+To consume the synchronous API, there are only a few function calls that need to be introduced:
+
+ redisContext *redisConnect(const char *ip, int port);
+ void *redisCommand(redisContext *c, const char *format, ...);
+ void freeReplyObject(void *reply);
+
+### Connecting
+
+The function `redisConnect` is used to create a so-called `redisContext`. The
+context is where Hiredis holds state for a connection. The `redisContext`
+struct has an integer `err` field that is non-zero when an the connection is in
+an error state. The field `errstr` will contain a string with a description of
+the error. More information on errors can be found in the **Errors** section.
+After trying to connect to Redis using `redisConnect` you should
+check the `err` field to see if establishing the connection was successful:
+
+ redisContext *c = redisConnect("127.0.0.1", 6379);
+ if (c->err) {
+ printf("Error: %s\n", c->errstr);
+ // handle error
+ }
+
+### Sending commands
+
+There are several ways to issue commands to Redis. The first that will be introduced is
+`redisCommand`. This function takes a format similar to printf. In the simplest form,
+it is used like this:
+
+ reply = redisCommand(context, "SET foo bar");
+
+The specifier `%s` interpolates a string in the command, and uses `strlen` to
+determine the length of the string:
+
+ reply = redisCommand(context, "SET foo %s", value);
+
+When you need to pass binary safe strings in a command, the `%b` specifier can be
+used. Together with a pointer to the string, it requires a `size_t` length argument
+of the string:
+
+ reply = redisCommand(context, "SET foo %b", value, valuelen);
+
+Internally, Hiredis splits the command in different arguments and will
+convert it to the protocol used to communicate with Redis.
+One or more spaces separates arguments, so you can use the specifiers
+anywhere in an argument:
+
+ reply = redisCommand("SET key:%s %s", myid, value);
+
+### Using replies
+
+The return value of `redisCommand` holds a reply when the command was
+successfully executed. When an error occurs, the return value is `NULL` and
+the `err` field in the context will be set (see section on **Errors**).
+Once an error is returned the context cannot be reused and you should set up
+a new connection.
+
+The standard replies that `redisCommand` are of the type `redisReply`. The
+`type` field in the `redisReply` should be used to test what kind of reply
+was received:
+
+* **`REDIS_REPLY_STATUS`**:
+ * The command replied with a status reply. The status string can be accessed using `reply->str`.
+ The length of this string can be accessed using `reply->len`.
+
+* **`REDIS_REPLY_ERROR`**:
+ * The command replied with an error. The error string can be accessed identical to `REDIS_REPLY_STATUS`.
+
+* **`REDIS_REPLY_INTEGER`**:
+ * The command replied with an integer. The integer value can be accessed using the
+ `reply->integer` field of type `long long`.
+
+* **`REDIS_REPLY_NIL`**:
+ * The command replied with a **nil** object. There is no data to access.
+
+* **`REDIS_REPLY_STRING`**:
+ * A bulk (string) reply. The value of the reply can be accessed using `reply->str`.
+ The length of this string can be accessed using `reply->len`.
+
+* **`REDIS_REPLY_ARRAY`**:
+ * A multi bulk reply. The number of elements in the multi bulk reply is stored in
+ `reply->elements`. Every element in the multi bulk reply is a `redisReply` object as well
+ and can be accessed via `reply->elements[..index..]`.
+ Redis may reply with nested arrays but this is fully supported.
+
+Replies should be freed using the `freeReplyObject()` function.
+Note that this function will take care of freeing sub-replies objects
+contained in arrays and nested arrays, so there is no need for the user to
+free the sub replies (it is actually harmful and will corrupt the memory).
+
+### Cleaning up
+
+To disconnect and free the context the following function can be used:
+
+ void redisFree(redisContext *c);
+
+This function immediately closes the socket and then free's the allocations done in
+creating the context.
+
+### Sending commands (cont'd)
+
+Together with `redisCommand`, the function `redisCommandArgv` can be used to issue commands.
+It has the following prototype:
+
+ void *redisCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
+
+It takes the number of arguments `argc`, an array of strings `argv` and the lengths of the
+arguments `argvlen`. For convenience, `argvlen` may be set to `NULL` and the function will
+use `strlen(3)` on every argument to determine its length. Obviously, when any of the arguments
+need to be binary safe, the entire array of lengths `argvlen` should be provided.
+
+The return value has the same semantic as `redisCommand`.
+
+### Pipelining
+
+To explain how Hiredis supports pipelining in a blocking connection, there needs to be
+understanding of the internal execution flow.
+
+When any of the functions in the `redisCommand` family is called, Hiredis first formats the
+command according to the Redis protocol. The formatted command is then put in the output buffer
+of the context. This output buffer is dynamic, so it can hold any number of commands.
+After the command is put in the output buffer, `redisGetReply` is called. This function has the
+following two execution paths:
+
+1. The input buffer is non-empty:
+ * Try to parse a single reply from the input buffer and return it
+ * If no reply could be parsed, continue at *2*
+2. The input buffer is empty:
+ * Write the **entire** output buffer to the socket
+ * Read from the socket until a single reply could be parsed
+
+The function `redisGetReply` is exported as part of the Hiredis API and can be used when a reply
+is expected on the socket. To pipeline commands, the only things that needs to be done is
+filling up the output buffer. For this cause, two commands can be used that are identical
+to the `redisCommand` family, apart from not returning a reply:
+
+ void redisAppendCommand(redisContext *c, const char *format, ...);
+ void redisAppendCommandArgv(redisContext *c, int argc, const char **argv, const size_t *argvlen);
+
+After calling either function one or more times, `redisGetReply` can be used to receive the
+subsequent replies. The return value for this function is either `REDIS_OK` or `REDIS_ERR`, where
+the latter means an error occurred while reading a reply. Just as with the other commands,
+the `err` field in the context can be used to find out what the cause of this error is.
+
+The following examples shows a simple pipeline (resulting in only a single call to `write(2)` and
+a single call to `read(2)`):
+
+ redisReply *reply;
+ redisAppendCommand(context,"SET foo bar");
+ redisAppendCommand(context,"GET foo");
+ redisGetReply(context,&reply); // reply for SET
+ freeReplyObject(reply);
+ redisGetReply(context,&reply); // reply for GET
+ freeReplyObject(reply);
+
+This API can also be used to implement a blocking subscriber:
+
+ reply = redisCommand(context,"SUBSCRIBE foo");
+ freeReplyObject(reply);
+ while(redisGetReply(context,&reply) == REDIS_OK) {
+ // consume message
+ freeReplyObject(reply);
+ }
+
+### Errors
+
+When a function call is not successful, depending on the function either `NULL` or `REDIS_ERR` is
+returned. The `err` field inside the context will be non-zero and set to one of the
+following constants:
+
+* **`REDIS_ERR_IO`**:
+ There was an I/O error while creating the connection, trying to write
+ to the socket or read from the socket. If you included `errno.h` in your
+ application, you can use the global `errno` variable to find out what is
+ wrong.
+
+* **`REDIS_ERR_EOF`**:
+ The server closed the connection which resulted in an empty read.
+
+* **`REDIS_ERR_PROTOCOL`**:
+ There was an error while parsing the protocol.
+
+* **`REDIS_ERR_OTHER`**:
+ Any other error. Currently, it is only used when a specified hostname to connect
+ to cannot be resolved.
+
+In every case, the `errstr` field in the context will be set to hold a string representation
+of the error.
+
+## Asynchronous API
+
+Hiredis comes with an asynchronous API that works easily with any event library.
+Examples are bundled that show using Hiredis with [libev](http://software.schmorp.de/pkg/libev.html)
+and [libevent](http://monkey.org/~provos/libevent/).
+
+### Connecting
+
+The function `redisAsyncConnect` can be used to establish a non-blocking connection to
+Redis. It returns a pointer to the newly created `redisAsyncContext` struct. The `err` field
+should be checked after creation to see if there were errors creating the connection.
+Because the connection that will be created is non-blocking, the kernel is not able to
+instantly return if the specified host and port is able to accept a connection.
+
+ redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
+ if (c->err) {
+ printf("Error: %s\n", c->errstr);
+ // handle error
+ }
+
+The asynchronous context can hold a disconnect callback function that is called when the
+connection is disconnected (either because of an error or per user request). This function should
+have the following prototype:
+
+ void(const redisAsyncContext *c, int status);
+
+On a disconnect, the `status` argument is set to `REDIS_OK` when disconnection was initiated by the
+user, or `REDIS_ERR` when the disconnection was caused by an error. When it is `REDIS_ERR`, the `err`
+field in the context can be accessed to find out the cause of the error.
+
+The context object is always free'd after the disconnect callback fired. When a reconnect is needed,
+the disconnect callback is a good point to do so.
+
+Setting the disconnect callback can only be done once per context. For subsequent calls it will
+return `REDIS_ERR`. The function to set the disconnect callback has the following prototype:
+
+ int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
+
+### Sending commands and their callbacks
+
+In an asynchronous context, commands are automatically pipelined due to the nature of an event loop.
+Therefore, unlike the synchronous API, there is only a single way to send commands.
+Because commands are sent to Redis asynchronously, issuing a command requires a callback function
+that is called when the reply is received. Reply callbacks should have the following prototype:
+
+ void(redisAsyncContext *c, void *reply, void *privdata);
+
+The `privdata` argument can be used to curry arbitrary data to the callback from the point where
+the command is initially queued for execution.
+
+The functions that can be used to issue commands in an asynchronous context are:
+
+ int redisAsyncCommand(
+ redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
+ const char *format, ...);
+ int redisAsyncCommandArgv(
+ redisAsyncContext *ac, redisCallbackFn *fn, void *privdata,
+ int argc, const char **argv, const size_t *argvlen);
+
+Both functions work like their blocking counterparts. The return value is `REDIS_OK` when the command
+was successfully added to the output buffer and `REDIS_ERR` otherwise. Example: when the connection
+is being disconnected per user-request, no new commands may be added to the output buffer and `REDIS_ERR` is
+returned on calls to the `redisAsyncCommand` family.
+
+If the reply for a command with a `NULL` callback is read, it is immediately free'd. When the callback
+for a command is non-`NULL`, it is responsible for cleaning up the reply.
+
+All pending callbacks are called with a `NULL` reply when the context encountered an error.
+
+### Disconnecting
+
+An asynchronous connection can be terminated using:
+
+ void redisAsyncDisconnect(redisAsyncContext *ac);
+
+When this function is called, the connection is **not** immediately terminated. Instead, new
+commands are no longer accepted and the connection is only terminated when all pending commands
+have been written to the socket, their respective replies have been read and their respective
+callbacks have been executed. After this, the disconnection callback is executed with the
+`REDIS_OK` status and the context object is free'd.
+
+### Hooking it up to event library *X*
+
+There are a few hooks that need to be set on the context object after it is created.
+See the `adapters/` directory for bindings to *libev* and *libevent*.
+
+## Reply parsing API
+
+To be done.
+
+## AUTHORS
+
+Hiredis was written by Salvatore Sanfilippo (antirez at gmail) and
+Pieter Noordhuis (pcnoordhuis at gmail) and is released under the BSD license.
2  node_modules/hiredis/deps/hiredis/TODO
@@ -0,0 +1,2 @@
+- add redisCommandVector()
+- add support for pipelining
95 node_modules/hiredis/deps/hiredis/adapters/ae.h
@@ -0,0 +1,95 @@
+#include <sys/types.h>
+#include <ae.h>
+#include "../hiredis.h"
+#include "../async.h"
+
+typedef struct redisAeEvents {
+ redisAsyncContext *context;
+ aeEventLoop *loop;
+ int fd;
+ int reading, writing;
+} redisAeEvents;
+
+void redisAeReadEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
+ ((void)el); ((void)fd); ((void)mask);
+
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ redisAsyncHandleRead(e->context);
+}
+
+void redisAeWriteEvent(aeEventLoop *el, int fd, void *privdata, int mask) {
+ ((void)el); ((void)fd); ((void)mask);
+
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ redisAsyncHandleWrite(e->context);
+}
+
+void redisAeAddRead(void *privdata) {
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ aeEventLoop *loop = e->loop;
+ if (!e->reading) {
+ e->reading = 1;
+ aeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e);
+ }
+}
+
+void redisAeDelRead(void *privdata) {
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ aeEventLoop *loop = e->loop;
+ if (e->reading) {
+ e->reading = 0;
+ aeDeleteFileEvent(loop,e->fd,AE_READABLE);
+ }
+}
+
+void redisAeAddWrite(void *privdata) {
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ aeEventLoop *loop = e->loop;
+ if (!e->writing) {
+ e->writing = 1;
+ aeCreateFileEvent(loop,e->fd,AE_WRITABLE,redisAeWriteEvent,e);
+ }
+}
+
+void redisAeDelWrite(void *privdata) {
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ aeEventLoop *loop = e->loop;
+ if (e->writing) {
+ e->writing = 0;
+ aeDeleteFileEvent(loop,e->fd,AE_WRITABLE);
+ }
+}
+
+void redisAeCleanup(void *privdata) {
+ redisAeEvents *e = (redisAeEvents*)privdata;
+ redisAeDelRead(privdata);
+ redisAeDelWrite(privdata);
+ free(e);
+}
+
+int redisAeAttach(aeEventLoop *loop, redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ redisAeEvents *e;
+
+ /* Nothing should be attached when something is already attached */
+ if (ac->ev.data != NULL)
+ return REDIS_ERR;
+
+ /* Create container for context and r/w events */
+ e = (redisAeEvents*)malloc(sizeof(*e));
+ e->context = ac;
+ e->loop = loop;
+ e->fd = c->fd;
+ e->reading = e->writing = 0;
+
+ /* Register functions to start/stop listening for events */
+ ac->ev.addRead = redisAeAddRead;
+ ac->ev.delRead = redisAeDelRead;
+ ac->ev.addWrite = redisAeAddWrite;
+ ac->ev.delWrite = redisAeDelWrite;
+ ac->ev.cleanup = redisAeCleanup;
+ ac->ev.data = e;
+
+ return REDIS_OK;
+}
+
113 node_modules/hiredis/deps/hiredis/adapters/libev.h
@@ -0,0 +1,113 @@
+#include <sys/types.h>
+#include <ev.h>
+#include "../hiredis.h"
+#include "../async.h"
+
+typedef struct redisLibevEvents {
+ redisAsyncContext *context;
+ struct ev_loop *loop;
+ int reading, writing;
+ ev_io rev, wev;
+} redisLibevEvents;
+
+void redisLibevReadEvent(EV_P_ ev_io *watcher, int revents) {
+#if EV_MULTIPLICITY
+ ((void)loop);
+#endif
+ ((void)revents);
+
+ redisLibevEvents *e = (redisLibevEvents*)watcher->data;
+ redisAsyncHandleRead(e->context);
+}
+
+void redisLibevWriteEvent(EV_P_ ev_io *watcher, int revents) {
+#if EV_MULTIPLICITY
+ ((void)loop);
+#endif
+ ((void)revents);
+
+ redisLibevEvents *e = (redisLibevEvents*)watcher->data;
+ redisAsyncHandleWrite(e->context);
+}
+
+void redisLibevAddRead(void *privdata) {
+ redisLibevEvents *e = (redisLibevEvents*)privdata;
+ struct ev_loop *loop = e->loop;
+ ((void)loop);
+ if (!e->reading) {
+ e->reading = 1;
+ ev_io_start(EV_A_ &e->rev);
+ }
+}
+
+void redisLibevDelRead(void *privdata) {
+ redisLibevEvents *e = (redisLibevEvents*)privdata;
+ struct ev_loop *loop = e->loop;
+ ((void)loop);
+ if (e->reading) {
+ e->reading = 0;
+ ev_io_stop(EV_A_ &e->rev);
+ }
+}
+
+void redisLibevAddWrite(void *privdata) {
+ redisLibevEvents *e = (redisLibevEvents*)privdata;
+ struct ev_loop *loop = e->loop;
+ ((void)loop);
+ if (!e->writing) {
+ e->writing = 1;
+ ev_io_start(EV_A_ &e->wev);
+ }
+}
+
+void redisLibevDelWrite(void *privdata) {
+ redisLibevEvents *e = (redisLibevEvents*)privdata;
+ struct ev_loop *loop = e->loop;
+ ((void)loop);
+ if (e->writing) {
+ e->writing = 0;
+ ev_io_stop(EV_A_ &e->wev);
+ }
+}
+
+void redisLibevCleanup(void *privdata) {
+ redisLibevEvents *e = (redisLibevEvents*)privdata;
+ redisLibevDelRead(privdata);
+ redisLibevDelWrite(privdata);
+ free(e);
+}
+
+int redisLibevAttach(EV_P_ redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ redisLibevEvents *e;
+
+ /* Nothing should be attached when something is already attached */
+ if (ac->ev.data != NULL)
+ return REDIS_ERR;
+
+ /* Create container for context and r/w events */
+ e = (redisLibevEvents*)malloc(sizeof(*e));
+ e->context = ac;
+#if EV_MULTIPLICITY
+ e->loop = loop;
+#else
+ e->loop = NULL;
+#endif
+ e->reading = e->writing = 0;
+ e->rev.data = e;
+ e->wev.data = e;
+
+ /* Register functions to start/stop listening for events */
+ ac->ev.addRead = redisLibevAddRead;
+ ac->ev.delRead = redisLibevDelRead;
+ ac->ev.addWrite = redisLibevAddWrite;
+ ac->ev.delWrite = redisLibevDelWrite;
+ ac->ev.cleanup = redisLibevCleanup;
+ ac->ev.data = e;
+
+ /* Initialize read/write events */
+ ev_io_init(&e->rev,redisLibevReadEvent,c->fd,EV_READ);
+ ev_io_init(&e->wev,redisLibevWriteEvent,c->fd,EV_WRITE);
+ return REDIS_OK;
+}
+
76 node_modules/hiredis/deps/hiredis/adapters/libevent.h
@@ -0,0 +1,76 @@
+#include <sys/types.h>
+#include <event.h>
+#include "../hiredis.h"
+#include "../async.h"
+
+typedef struct redisLibeventEvents {
+ redisAsyncContext *context;
+ struct event rev, wev;
+} redisLibeventEvents;
+
+void redisLibeventReadEvent(int fd, short event, void *arg) {
+ ((void)fd); ((void)event);
+ redisLibeventEvents *e = (redisLibeventEvents*)arg;
+ redisAsyncHandleRead(e->context);
+}
+
+void redisLibeventWriteEvent(int fd, short event, void *arg) {
+ ((void)fd); ((void)event);
+ redisLibeventEvents *e = (redisLibeventEvents*)arg;
+ redisAsyncHandleWrite(e->context);
+}
+
+void redisLibeventAddRead(void *privdata) {
+ redisLibeventEvents *e = (redisLibeventEvents*)privdata;
+ event_add(&e->rev,NULL);
+}
+
+void redisLibeventDelRead(void *privdata) {
+ redisLibeventEvents *e = (redisLibeventEvents*)privdata;
+ event_del(&e->rev);
+}
+
+void redisLibeventAddWrite(void *privdata) {
+ redisLibeventEvents *e = (redisLibeventEvents*)privdata;
+ event_add(&e->wev,NULL);
+}
+
+void redisLibeventDelWrite(void *privdata) {
+ redisLibeventEvents *e = (redisLibeventEvents*)privdata;
+ event_del(&e->wev);
+}
+
+void redisLibeventCleanup(void *privdata) {
+ redisLibeventEvents *e = (redisLibeventEvents*)privdata;
+ event_del(&e->rev);
+ event_del(&e->wev);
+ free(e);
+}
+
+int redisLibeventAttach(redisAsyncContext *ac, struct event_base *base) {
+ redisContext *c = &(ac->c);
+ redisLibeventEvents *e;
+
+ /* Nothing should be attached when something is already attached */
+ if (ac->ev.data != NULL)
+ return REDIS_ERR;
+
+ /* Create container for context and r/w events */
+ e = (redisLibeventEvents*)malloc(sizeof(*e));
+ e->context = ac;
+
+ /* Register functions to start/stop listening for events */
+ ac->ev.addRead = redisLibeventAddRead;
+ ac->ev.delRead = redisLibeventDelRead;
+ ac->ev.addWrite = redisLibeventAddWrite;
+ ac->ev.delWrite = redisLibeventDelWrite;
+ ac->ev.cleanup = redisLibeventCleanup;
+ ac->ev.data = e;
+
+ /* Initialize and install read/write events */
+ event_set(&e->rev,c->fd,EV_READ,redisLibeventReadEvent,e);
+ event_set(&e->wev,c->fd,EV_WRITE,redisLibeventWriteEvent,e);
+ event_base_set(base,&e->rev);
+ event_base_set(base,&e->wev);
+ return REDIS_OK;
+}
545 node_modules/hiredis/deps/hiredis/async.c
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <string.h>
+#include <strings.h>
+#include <assert.h>
+#include <ctype.h>
+#include "async.h"
+#include "dict.c"
+#include "sds.h"
+#include "util.h"
+
+/* Forward declaration of function in hiredis.c */
+void __redisAppendCommand(redisContext *c, char *cmd, size_t len);
+
+/* Functions managing dictionary of callbacks for pub/sub. */
+static unsigned int callbackHash(const void *key) {
+ return dictGenHashFunction((unsigned char*)key,sdslen((char*)key));
+}
+
+static void *callbackValDup(void *privdata, const void *src) {
+ ((void) privdata);
+ redisCallback *dup = malloc(sizeof(*dup));
+ memcpy(dup,src,sizeof(*dup));
+ return dup;
+}
+
+static int callbackKeyCompare(void *privdata, const void *key1, const void *key2) {
+ int l1, l2;
+ ((void) privdata);
+
+ l1 = sdslen((sds)key1);
+ l2 = sdslen((sds)key2);
+ if (l1 != l2) return 0;
+ return memcmp(key1,key2,l1) == 0;
+}
+
+static void callbackKeyDestructor(void *privdata, void *key) {
+ ((void) privdata);
+ sdsfree((sds)key);
+}
+
+static void callbackValDestructor(void *privdata, void *val) {
+ ((void) privdata);
+ free(val);
+}
+
+static dictType callbackDict = {
+ callbackHash,
+ NULL,
+ callbackValDup,
+ callbackKeyCompare,
+ callbackKeyDestructor,
+ callbackValDestructor
+};
+
+static redisAsyncContext *redisAsyncInitialize(redisContext *c) {
+ redisAsyncContext *ac = realloc(c,sizeof(redisAsyncContext));
+ c = &(ac->c);
+
+ /* The regular connect functions will always set the flag REDIS_CONNECTED.
+ * For the async API, we want to wait until the first write event is
+ * received up before setting this flag, so reset it here. */
+ c->flags &= ~REDIS_CONNECTED;
+
+ ac->err = 0;
+ ac->errstr = NULL;
+ ac->data = NULL;
+
+ ac->ev.data = NULL;
+ ac->ev.addRead = NULL;
+ ac->ev.delRead = NULL;
+ ac->ev.addWrite = NULL;
+ ac->ev.delWrite = NULL;
+ ac->ev.cleanup = NULL;
+
+ ac->onConnect = NULL;
+ ac->onDisconnect = NULL;
+
+ ac->replies.head = NULL;
+ ac->replies.tail = NULL;
+ ac->sub.invalid.head = NULL;
+ ac->sub.invalid.tail = NULL;
+ ac->sub.channels = dictCreate(&callbackDict,NULL);
+ ac->sub.patterns = dictCreate(&callbackDict,NULL);
+ return ac;
+}
+
+/* We want the error field to be accessible directly instead of requiring
+ * an indirection to the redisContext struct. */
+static void __redisAsyncCopyError(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ ac->err = c->err;
+ ac->errstr = c->errstr;
+}
+
+redisAsyncContext *redisAsyncConnect(const char *ip, int port) {
+ redisContext *c = redisConnectNonBlock(ip,port);
+ redisAsyncContext *ac = redisAsyncInitialize(c);
+ __redisAsyncCopyError(ac);
+ return ac;
+}
+
+redisAsyncContext *redisAsyncConnectUnix(const char *path) {
+ redisContext *c = redisConnectUnixNonBlock(path);
+ redisAsyncContext *ac = redisAsyncInitialize(c);
+ __redisAsyncCopyError(ac);
+ return ac;
+}
+
+int redisAsyncSetReplyObjectFunctions(redisAsyncContext *ac, redisReplyObjectFunctions *fn) {
+ redisContext *c = &(ac->c);
+ return redisSetReplyObjectFunctions(c,fn);
+}
+
+int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn) {
+ if (ac->onConnect == NULL) {
+ ac->onConnect = fn;
+
+ /* The common way to detect an established connection is to wait for
+ * the first write event to be fired. This assumes the related event
+ * library functions are already set. */
+ if (ac->ev.addWrite) ac->ev.addWrite(ac->ev.data);
+ return REDIS_OK;
+ }
+ return REDIS_ERR;
+}
+
+int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn) {
+ if (ac->onDisconnect == NULL) {
+ ac->onDisconnect = fn;
+ return REDIS_OK;
+ }
+ return REDIS_ERR;
+}
+
+/* Helper functions to push/shift callbacks */
+static int __redisPushCallback(redisCallbackList *list, redisCallback *source) {
+ redisCallback *cb;
+
+ /* Copy callback from stack to heap */
+ cb = malloc(sizeof(*cb));
+ if (!cb) redisOOM();
+ if (source != NULL) {
+ memcpy(cb,source,sizeof(*cb));
+ cb->next = NULL;
+ }
+
+ /* Store callback in list */
+ if (list->head == NULL)
+ list->head = cb;
+ if (list->tail != NULL)
+ list->tail->next = cb;
+ list->tail = cb;
+ return REDIS_OK;
+}
+
+static int __redisShiftCallback(redisCallbackList *list, redisCallback *target) {
+ redisCallback *cb = list->head;
+ if (cb != NULL) {
+ list->head = cb->next;
+ if (cb == list->tail)
+ list->tail = NULL;
+
+ /* Copy callback from heap to stack */
+ if (target != NULL)
+ memcpy(target,cb,sizeof(*cb));
+ free(cb);
+ return REDIS_OK;
+ }
+ return REDIS_ERR;
+}
+
+static void __redisRunCallback(redisAsyncContext *ac, redisCallback *cb, redisReply *reply) {
+ redisContext *c = &(ac->c);
+ if (cb->fn != NULL) {
+ c->flags |= REDIS_IN_CALLBACK;
+ cb->fn(ac,reply,cb->privdata);
+ c->flags &= ~REDIS_IN_CALLBACK;
+ }
+}
+
+/* Helper function to free the context. */
+static void __redisAsyncFree(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ redisCallback cb;
+ dictIterator *it;
+ dictEntry *de;
+
+ /* Execute pending callbacks with NULL reply. */
+ while (__redisShiftCallback(&ac->replies,&cb) == REDIS_OK)
+ __redisRunCallback(ac,&cb,NULL);
+
+ /* Execute callbacks for invalid commands */
+ while (__redisShiftCallback(&ac->sub.invalid,&cb) == REDIS_OK)
+ __redisRunCallback(ac,&cb,NULL);
+
+ /* Run subscription callbacks callbacks with NULL reply */
+ it = dictGetIterator(ac->sub.channels);
+ while ((de = dictNext(it)) != NULL)
+ __redisRunCallback(ac,dictGetEntryVal(de),NULL);
+ dictReleaseIterator(it);
+ dictRelease(ac->sub.channels);
+
+ it = dictGetIterator(ac->sub.patterns);
+ while ((de = dictNext(it)) != NULL)
+ __redisRunCallback(ac,dictGetEntryVal(de),NULL);
+ dictReleaseIterator(it);
+ dictRelease(ac->sub.patterns);
+
+ /* Signal event lib to clean up */
+ if (ac->ev.cleanup) ac->ev.cleanup(ac->ev.data);
+
+ /* Execute disconnect callback. When redisAsyncFree() initiated destroying
+ * this context, the status will always be REDIS_OK. */
+ if (ac->onDisconnect && (c->flags & REDIS_CONNECTED)) {
+ if (c->flags & REDIS_FREEING) {
+ ac->onDisconnect(ac,REDIS_OK);
+ } else {
+ ac->onDisconnect(ac,(ac->err == 0) ? REDIS_OK : REDIS_ERR);
+ }
+ }
+
+ /* Cleanup self */
+ redisFree(c);
+}
+
+/* Free the async context. When this function is called from a callback,
+ * control needs to be returned to redisProcessCallbacks() before actual
+ * free'ing. To do so, a flag is set on the context which is picked up by
+ * redisProcessCallbacks(). Otherwise, the context is immediately free'd. */
+void redisAsyncFree(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ c->flags |= REDIS_FREEING;
+ if (!(c->flags & REDIS_IN_CALLBACK))
+ __redisAsyncFree(ac);
+}
+
+/* Helper function to make the disconnect happen and clean up. */
+static void __redisAsyncDisconnect(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+
+ /* Make sure error is accessible if there is any */
+ __redisAsyncCopyError(ac);
+
+ if (ac->err == 0) {
+ /* For clean disconnects, there should be no pending callbacks. */
+ assert(__redisShiftCallback(&ac->replies,NULL) == REDIS_ERR);
+ } else {
+ /* Disconnection is caused by an error, make sure that pending
+ * callbacks cannot call new commands. */
+ c->flags |= REDIS_DISCONNECTING;
+ }
+
+ /* For non-clean disconnects, __redisAsyncFree() will execute pending
+ * callbacks with a NULL-reply. */
+ __redisAsyncFree(ac);
+}
+
+/* Tries to do a clean disconnect from Redis, meaning it stops new commands
+ * from being issued, but tries to flush the output buffer and execute
+ * callbacks for all remaining replies. When this function is called from a
+ * callback, there might be more replies and we can safely defer disconnecting
+ * to redisProcessCallbacks(). Otherwise, we can only disconnect immediately
+ * when there are no pending callbacks. */
+void redisAsyncDisconnect(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ c->flags |= REDIS_DISCONNECTING;
+ if (!(c->flags & REDIS_IN_CALLBACK) && ac->replies.head == NULL)
+ __redisAsyncDisconnect(ac);
+}
+
+static int __redisGetSubscribeCallback(redisAsyncContext *ac, redisReply *reply, redisCallback *dstcb) {
+ redisContext *c = &(ac->c);
+ dict *callbacks;
+ dictEntry *de;
+ int pvariant;
+ char *stype;
+ sds sname;
+
+ /* Custom reply functions are not supported for pub/sub. This will fail
+ * very hard when they are used... */
+ if (reply->type == REDIS_REPLY_ARRAY) {
+ assert(reply->elements >= 2);
+ assert(reply->element[0]->type == REDIS_REPLY_STRING);
+ stype = reply->element[0]->str;
+ pvariant = (tolower(stype[0]) == 'p') ? 1 : 0;
+
+ if (pvariant)
+ callbacks = ac->sub.patterns;
+ else
+ callbacks = ac->sub.channels;
+
+ /* Locate the right callback */
+ assert(reply->element[1]->type == REDIS_REPLY_STRING);
+ sname = sdsnewlen(reply->element[1]->str,reply->element[1]->len);
+ de = dictFind(callbacks,sname);
+ if (de != NULL) {
+ memcpy(dstcb,dictGetEntryVal(de),sizeof(*dstcb));
+
+ /* If this is an unsubscribe message, remove it. */
+ if (strcasecmp(stype+pvariant,"unsubscribe") == 0) {
+ dictDelete(callbacks,sname);
+
+ /* If this was the last unsubscribe message, revert to
+ * non-subscribe mode. */
+ assert(reply->element[2]->type == REDIS_REPLY_INTEGER);
+ if (reply->element[2]->integer == 0)
+ c->flags &= ~REDIS_SUBSCRIBED;
+ }
+ }
+ sdsfree(sname);
+ } else {
+ /* Shift callback for invalid commands. */
+ __redisShiftCallback(&ac->sub.invalid,dstcb);
+ }
+ return REDIS_OK;
+}
+
+void redisProcessCallbacks(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ redisCallback cb;
+ void *reply = NULL;
+ int status;
+
+ while((status = redisGetReply(c,&reply)) == REDIS_OK) {
+ if (reply == NULL) {
+ /* When the connection is being disconnected and there are
+ * no more replies, this is the cue to really disconnect. */
+ if (c->flags & REDIS_DISCONNECTING && sdslen(c->obuf) == 0) {
+ __redisAsyncDisconnect(ac);
+ return;
+ }
+
+ /* When the connection is not being disconnected, simply stop
+ * trying to get replies and wait for the next loop tick. */
+ break;
+ }
+
+ /* Even if the context is subscribed, pending regular callbacks will
+ * get a reply before pub/sub messages arrive. */
+ if (__redisShiftCallback(&ac->replies,&cb) != REDIS_OK) {
+ /* No more regular callbacks, the context *must* be subscribed. */
+ assert(c->flags & REDIS_SUBSCRIBED);
+ __redisGetSubscribeCallback(ac,reply,&cb);
+ }
+
+ if (cb.fn != NULL) {
+ __redisRunCallback(ac,&cb,reply);
+ c->fn->freeObject(reply);
+
+ /* Proceed with free'ing when redisAsyncFree() was called. */
+ if (c->flags & REDIS_FREEING) {
+ __redisAsyncFree(ac);
+ return;
+ }
+ } else {
+ /* No callback for this reply. This can either be a NULL callback,
+ * or there were no callbacks to begin with. Either way, don't
+ * abort with an error, but simply ignore it because the client
+ * doesn't know what the server will spit out over the wire. */
+ c->fn->freeObject(reply);
+ }
+ }
+
+ /* Disconnect when there was an error reading the reply */
+ if (status != REDIS_OK)
+ __redisAsyncDisconnect(ac);
+}
+
+/* This function should be called when the socket is readable.
+ * It processes all replies that can be read and executes their callbacks.
+ */
+void redisAsyncHandleRead(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+
+ if (redisBufferRead(c) == REDIS_ERR) {
+ __redisAsyncDisconnect(ac);
+ } else {
+ /* Always re-schedule reads */
+ if (ac->ev.addRead) ac->ev.addRead(ac->ev.data);
+ redisProcessCallbacks(ac);
+ }
+}
+
+void redisAsyncHandleWrite(redisAsyncContext *ac) {
+ redisContext *c = &(ac->c);
+ int done = 0;
+
+ if (redisBufferWrite(c,&done) == REDIS_ERR) {
+ __redisAsyncDisconnect(ac);
+ } else {
+ /* Continue writing when not done, stop writing otherwise */
+ if (!done) {
+ if (ac->ev.addWrite) ac->ev.addWrite(ac->ev.data);
+ } else {
+ if (ac->ev.delWrite) ac->ev.delWrite(ac->ev.data);
+ }
+
+ /* Always schedule reads after writes */
+ if (ac->ev.addRead) ac->ev.addRead(ac->ev.data);
+
+ /* Fire onConnect when this is the first write event. */
+ if (!(c->flags & REDIS_CONNECTED)) {
+ c->flags |= REDIS_CONNECTED;
+ if (ac->onConnect) ac->onConnect(ac);
+ }
+ }
+}
+
+/* Sets a pointer to the first argument and its length starting at p. Returns
+ * the number of bytes to skip to get to the following argument. */
+static char *nextArgument(char *start, char **str, size_t *len) {
+ char *p = start;
+ if (p[0] != '$') {
+ p = strchr(p,'$');
+ if (p == NULL) return NULL;
+ }
+
+ *len = (int)strtol(p+1,NULL,10);
+ p = strchr(p,'\r');
+ assert(p);
+ *str = p+2;
+ return p+2+(*len)+2;
+}
+
+/* Helper function for the redisAsyncCommand* family of functions. Writes a
+ * formatted command to the output buffer and registers the provided callback
+ * function with the context. */
+static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, char *cmd, size_t len) {
+ redisContext *c = &(ac->c);
+ redisCallback cb;
+ int pvariant, hasnext;
+ char *cstr, *astr;
+ size_t clen, alen;
+ char *p;
+ sds sname;
+
+ /* Don't accept new commands when the connection is about to be closed. */
+ if (c->flags & (REDIS_DISCONNECTING | REDIS_FREEING)) return REDIS_ERR;
+
+ /* Setup callback */
+ cb.fn = fn;
+ cb.privdata = privdata;
+
+ /* Find out which command will be appended. */
+ p = nextArgument(cmd,&cstr,&clen);
+ assert(p != NULL);
+ hasnext = (p[0] == '$');
+ pvariant = (tolower(cstr[0]) == 'p') ? 1 : 0;
+ cstr += pvariant;
+ clen -= pvariant;
+
+ if (hasnext && strncasecmp(cstr,"subscribe\r\n",11) == 0) {
+ c->flags |= REDIS_SUBSCRIBED;
+
+ /* Add every channel/pattern to the list of subscription callbacks. */
+ while ((p = nextArgument(p,&astr,&alen)) != NULL) {
+ sname = sdsnewlen(astr,alen);
+ if (pvariant)
+ dictReplace(ac->sub.patterns,sname,&cb);
+ else
+ dictReplace(ac->sub.channels,sname,&cb);
+ }
+ } else if (strncasecmp(cstr,"unsubscribe\r\n",13) == 0) {
+ /* It is only useful to call (P)UNSUBSCRIBE when the context is
+ * subscribed to one or more channels or patterns. */
+ if (!(c->flags & REDIS_SUBSCRIBED)) return REDIS_ERR;
+
+ /* (P)UNSUBSCRIBE does not have its own response: every channel or
+ * pattern that is unsubscribed will receive a message. This means we
+ * should not append a callback function for this command. */
+ } else {
+ if (c->flags & REDIS_SUBSCRIBED)
+ /* This will likely result in an error reply, but it needs to be
+ * received and passed to the callback. */
+ __redisPushCallback(&ac->sub.invalid,&cb);
+ else
+ __redisPushCallback(&ac->replies,&cb);
+ }
+
+ __redisAppendCommand(c,cmd,len);
+
+ /* Always schedule a write when the write buffer is non-empty */
+ if (ac->ev.addWrite) ac->ev.addWrite(ac->ev.data);
+
+ return REDIS_OK;
+}
+
+int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap) {
+ char *cmd;
+ int len;
+ int status;
+ len = redisvFormatCommand(&cmd,format,ap);
+ status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
+ free(cmd);
+ return status;
+}
+
+int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...) {
+ va_list ap;
+ int status;
+ va_start(ap,format);
+ status = redisvAsyncCommand(ac,fn,privdata,format,ap);
+ va_end(ap);
+ return status;
+}
+
+int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen) {
+ char *cmd;
+ int len;
+ int status;
+ len = redisFormatCommandArgv(&cmd,argc,argv,argvlen);
+ status = __redisAsyncCommand(ac,fn,privdata,cmd,len);
+ free(cmd);
+ return status;
+}
126 node_modules/hiredis/deps/hiredis/async.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * Copyright (c) 2010, Pieter Noordhuis <pcnoordhuis at gmail dot com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __HIREDIS_ASYNC_H
+#define __HIREDIS_ASYNC_H
+#include "hiredis.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct redisAsyncContext; /* need forward declaration of redisAsyncContext */
+struct dict; /* dictionary header is included in async.c */
+
+/* Reply callback prototype and container */
+typedef void (redisCallbackFn)(struct redisAsyncContext*, void*, void*);
+typedef struct redisCallback {
+ struct redisCallback *next; /* simple singly linked list */
+ redisCallbackFn *fn;
+ void *privdata;
+} redisCallback;
+
+/* List of callbacks for either regular replies or pub/sub */
+typedef struct redisCallbackList {
+ redisCallback *head, *tail;
+} redisCallbackList;
+
+/* Connection callback prototypes */
+typedef void (redisDisconnectCallback)(const struct redisAsyncContext*, int status);
+typedef void (redisConnectCallback)(const struct redisAsyncContext*);
+
+/* Context for an async connection to Redis */
+typedef struct redisAsyncContext {
+ /* Hold the regular context, so it can be realloc'ed. */
+ redisContext c;
+
+ /* Setup error flags so they can be used directly. */
+ int err;
+ char *errstr;
+
+ /* Not used by hiredis */
+ void *data;
+
+ /* Event library data and hooks */
+ struct {
+ void *data;
+
+ /* Hooks that are called when the library expects to start
+ * reading/writing. These functions should be idempotent. */
+ void (*addRead)(void *privdata);
+ void (*delRead)(void *privdata);
+ void (*addWrite)(void *privdata);
+ void (*delWrite)(void *privdata);
+ void (*cleanup)(void *privdata);
+ } ev;
+
+ /* Called when either the connection is terminated due to an error or per
+ * user request. The status is set accordingly (REDIS_OK, REDIS_ERR). */
+ redisDisconnectCallback *onDisconnect;
+
+ /* Called when the first write event was received. */
+ redisConnectCallback *onConnect;
+
+ /* Regular command callbacks */
+ redisCallbackList replies;
+
+ /* Subscription callbacks */
+ struct {
+ redisCallbackList invalid;
+ struct dict *channels;
+ struct dict *patterns;
+ } sub;
+} redisAsyncContext;
+
+/* Functions that proxy to hiredis */
+redisAsyncContext *redisAsyncConnect(const char *ip, int port);
+redisAsyncContext *redisAsyncConnectUnix(const char *path);
+int redisAsyncSetReplyObjectFunctions(redisAsyncContext *ac, redisReplyObjectFunctions *fn);
+int redisAsyncSetConnectCallback(redisAsyncContext *ac, redisConnectCallback *fn);
+int redisAsyncSetDisconnectCallback(redisAsyncContext *ac, redisDisconnectCallback *fn);
+void redisAsyncDisconnect(redisAsyncContext *ac);
+void redisAsyncFree(redisAsyncContext *ac);
+
+/* Handle read/write events */
+void redisAsyncHandleRead(redisAsyncContext *ac);
+void redisAsyncHandleWrite(redisAsyncContext *ac);
+
+/* Command functions for an async context. Write the command to the
+ * output buffer and register the provided callback. */
+int redisvAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, va_list ap);
+int redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *format, ...);
+int redisAsyncCommandArgv(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, int argc, const char **argv, const size_t *argvlen);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
338 node_modules/hiredis/deps/hiredis/dict.c
@@ -0,0 +1,338 @@
+/* Hash table implementation.
+ *
+ * This file implements in memory hash tables with insert/del/replace/find/
+ * get-random-element operations. Hash tables will auto resize if needed
+ * tables of power of two in size are used, collisions are handled by
+ * chaining. See the source code for more information... :)
+ *
+ * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "fmacros.h"
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+#include "dict.h"
+
+/* -------------------------- private prototypes ---------------------------- */
+
+static int _dictExpandIfNeeded(dict *ht);
+static unsigned long _dictNextPower(unsigned long size);
+static int _dictKeyIndex(dict *ht, const void *key);
+static int _dictInit(dict *ht, dictType *type, void *privDataPtr);
+
+/* -------------------------- hash functions -------------------------------- */
+
+/* Generic hash function (a popular one from Bernstein).
+ * I tested a few and this was the best. */
+static unsigned int dictGenHashFunction(const unsigned char *buf, int len) {
+ unsigned int hash = 5381;
+
+ while (len--)
+ hash = ((hash << 5) + hash) + (*buf++); /* hash * 33 + c */
+ return hash;
+}
+
+/* ----------------------------- API implementation ------------------------- */
+
+/* Reset an hashtable already initialized with ht_init().
+ * NOTE: This function should only called by ht_destroy(). */
+static void _dictReset(dict *ht) {
+ ht->table = NULL;
+ ht->size = 0;
+ ht->sizemask = 0;
+ ht->used = 0;
+}
+
+/* Create a new hash table */
+static dict *dictCreate(dictType *type, void *privDataPtr) {
+ dict *ht = malloc(sizeof(*ht));
+ _dictInit(ht,type,privDataPtr);
+ return ht;
+}
+
+/* Initialize the hash table */
+static int _dictInit(dict *ht, dictType *type, void *privDataPtr) {
+ _dictReset(ht);
+ ht->type = type;
+ ht->privdata = privDataPtr;
+ return DICT_OK;
+}
+
+/* Expand or create the hashtable */
+static int dictExpand(dict *ht, unsigned long size) {
+ dict n; /* the new hashtable */
+ unsigned long realsize = _dictNextPower(size), i;
+
+ /* the size is invalid if it is smaller than the number of
+ * elements already inside the hashtable */
+ if (ht->used > size)
+ return DICT_ERR;
+
+ _dictInit(&n, ht->type, ht->privdata);
+ n.size = realsize;
+ n.sizemask = realsize-1;
+ n.table = calloc(realsize,sizeof(dictEntry*));
+
+ /* Copy all the elements from the old to the new table:
+ * note that if the old hash table is empty ht->size is zero,
+ * so dictExpand just creates an hash table. */
+ n.used = ht->used;
+ for (i = 0; i < ht->size && ht->used > 0; i++) {
+ dictEntry *he, *nextHe;
+
+ if (ht->table[i] == NULL) continue;
+
+ /* For each hash entry on this slot... */
+ he = ht->table[i];
+ while(he) {
+ unsigned int h;
+
+ nextHe = he->next;
+ /* Get the new element index */
+ h = dictHashKey(ht, he->key) & n.sizemask;
+ he->next = n.table[h];
+ n.table[h] = he;
+ ht->used--;
+ /* Pass to the next element */
+ he = nextHe;
+ }
+ }
+ assert(ht->used == 0);
+ free(ht->table);
+
+ /* Remap the new hashtable in the old */
+ *ht = n;
+ return DICT_OK;
+}
+
+/* Add an element to the target hash table */
+static int dictAdd(dict *ht, void *key, void *val) {
+ int index;
+ dictEntry *entry;
+
+ /* Get the index of the new element, or -1 if
+ * the element already exists. */
+ if ((index = _dictKeyIndex(ht, key)) == -1)
+ return DICT_ERR;
+
+ /* Allocates the memory and stores key */
+ entry = malloc(sizeof(*entry));
+ entry->next = ht->table[index];
+ ht->table[index] = entry;
+
+ /* Set the hash entry fields. */
+ dictSetHashKey(ht, entry, key);
+ dictSetHashVal(ht, entry, val);
+ ht->used++;
+ return DICT_OK;
+}
+
+/* Add an element, discarding the old if the key already exists.
+ * Return 1 if the key was added from scratch, 0 if there was already an
+ * element with such key and dictReplace() just performed a value update
+ * operation. */
+static int dictReplace(dict *ht, void *key, void *val) {
+ dictEntry *entry, auxentry;
+
+ /* Try to add the element. If the key
+ * does not exists dictAdd will suceed. */
+ if (dictAdd(ht, key, val) == DICT_OK)
+ return 1;
+ /* It already exists, get the entry */
+ entry = dictFind(ht, key);
+ /* Free the old value and set the new one */
+ /* Set the new value and free the old one. Note that it is important
+ * to do that in this order, as the value may just be exactly the same
+ * as the previous one. In this context, think to reference counting,
+ * you want to increment (set), and then decrement (free), and not the
+ * reverse. */
+ auxentry = *entry;
+ dictSetHashVal(ht, entry, val);
+ dictFreeEntryVal(ht, &auxentry);
+ return 0;
+}
+
+/* Search and remove an element */
+static int dictDelete(dict *ht, const void *key) {
+ unsigned int h;
+ dictEntry *de, *prevde;
+
+ if (ht->size == 0)
+ return DICT_ERR;
+ h = dictHashKey(ht, key) & ht->sizemask;
+ de = ht->table[h];
+
+ prevde = NULL;
+ while(de) {
+ if (dictCompareHashKeys(ht,key,de->key)) {
+ /* Unlink the element from the list */
+ if (prevde)
+ prevde->next = de->next;
+ else
+ ht->table[h] = de->next;
+
+ dictFreeEntryKey(ht,de);
+ dictFreeEntryVal(ht,de);
+ free(de);
+ ht->used--;
+ return DICT_OK;
+ }
+ prevde = de;
+ de = de->next;
+ }
+ return DICT_ERR; /* not found */
+}
+
+/* Destroy an entire hash table */
+static int _dictClear(dict *ht) {
+ unsigned long i;
+
+ /* Free all the elements */
+ for (i = 0; i < ht->size && ht->used > 0; i++) {
+ dictEntry *he, *nextHe;
+
+ if ((he = ht->table[i]) == NULL) continue;
+ while(he) {
+ nextHe = he->next;
+ dictFreeEntryKey(ht, he);
+ dictFreeEntryVal(ht, he);
+ free(he);
+ ht->used--;
+ he = nextHe;
+ }
+ }
+ /* Free the table and the allocated cache structure */
+ free(ht->table);
+ /* Re-initialize the table */
+ _dictReset(ht);
+ return DICT_OK; /* never fails */
+}
+
+/* Clear & Release the hash table */
+static void dictRelease(dict *ht) {
+ _dictClear(ht);
+ free(ht);
+}
+
+static dictEntry *dictFind(dict *ht, const void *key) {
+ dictEntry *he;
+ unsigned int h;
+
+ if (ht->size == 0) return NULL;
+ h = dictHashKey(ht, key) & ht->sizemask;
+ he = ht->table[h];
+ while(he) {
+ if (dictCompareHashKeys(ht, key, he->key))
+ return he;
+ he = he->next;
+ }
+ return NULL;
+}
+
+static dictIterator *dictGetIterator(dict *ht) {
+ dictIterator *iter = malloc(sizeof(*iter));
+
+ iter->ht = ht;
+ iter->index = -1;
+ iter->entry = NULL;
+ iter->nextEntry = NULL;
+ return iter;
+}
+
+static dictEntry *dictNext(dictIterator *iter) {
+ while (1) {
+ if (iter->entry == NULL) {
+ iter->index++;
+ if (iter->index >=
+ (signed)iter->ht->size) break;
+ iter->entry = iter->ht->table[iter->index];
+ } else {
+ iter->entry = iter->nextEntry;
+ }
+ if (iter->entry) {
+ /* We need to save the 'next' here, the iterator user
+ * may delete the entry we are returning. */
+ iter->nextEntry = iter->entry->next;
+ return iter->entry;
+ }
+ }
+ return NULL;
+}
+
+static void dictReleaseIterator(dictIterator *iter) {
+ free(iter);
+}
+
+/* ------------------------- private functions ------------------------------ */
+
+/* Expand the hash table if needed */
+static int _dictExpandIfNeeded(dict *ht) {
+ /* If the hash table is empty expand it to the intial size,
+ * if the table is "full" dobule its size. */
+ if (ht->size == 0)
+ return dictExpand(ht, DICT_HT_INITIAL_SIZE);
+ if (ht->used == ht->size)
+ return dictExpand(ht, ht->size*2);
+ return DICT_OK;
+}
+
+/* Our hash table capability is a power of two */
+static unsigned long _dictNextPower(unsigned long size) {
+ unsigned long i = DICT_HT_INITIAL_SIZE;
+
+ if (size >= LONG_MAX) return LONG_MAX;
+ while(1) {
+ if (i >= size)
+ return i;
+ i *= 2;
+ }
+}
+
+/* Returns the index of a free slot that can be populated with
+ * an hash entry for the given 'key'.
+ * If the key already exists, -1 is returned. */
+static int _dictKeyIndex(dict *ht, const void *key) {
+ unsigned int h;
+ dictEntry *he;
+
+ /* Expand the hashtable if needed */
+ if (_dictExpandIfNeeded(ht) == DICT_ERR)
+ return -1;
+ /* Compute the key hash value */
+ h = dictHashKey(ht, key) & ht->sizemask;
+ /* Search if this slot does not already contain the given key */
+ he = ht->table[h];
+ while(he) {
+ if (dictCompareHashKeys(ht, key, he->key))
+ return -1;
+ he = he->next;
+ }
+ return h;
+}
+
126 node_modules/hiredis/deps/hiredis/dict.h
@@ -0,0 +1,126 @@
+/* Hash table implementation.
+ *
+ * This file implements in memory hash tables with insert/del/replace/find/
+ * get-random-element operations. Hash tables will auto resize if needed
+ * tables of power of two in size are used, collisions are handled by
+ * chaining. See the source code for more information... :)
+ *
+ * Copyright (c) 2006-2010, Salvatore Sanfilippo <antirez at gmail dot com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Redis nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DICT_H
+#define __DICT_H
+
+#define DICT_OK 0
+#define DICT_ERR 1
+
+/* Unused arguments generate annoying warnings... */
+#define DICT_NOTUSED(V) ((void) V)
+
+typedef struct dictEntry {
+ void *key;
+ void *val;
+ struct dictEntry *next;
+} dictEntry;
+
+typedef struct dictType {
+ unsigned int (*hashFunction)(const void *key);
+ void *(*keyDup)(void *privdata, const void *key);
+ void *(*valDup)(void *privdata, const void *obj);
+ int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+ void (*keyDestructor)(void *privdata, void *key);
+ void (*valDestructor)(void *privdata, void *obj);
+} dictType;
+
+typedef struct dict {
+ dictEntry **table;
+ dictType *type;
+ unsigned long size;
+ unsigned long sizemask;
+ unsigned long used;
+ void *privdata;
+} dict;
+
+typedef struct dictIterator {
+ dict *ht;
+ int index;
+ dictEntry *entry, *nextEntry;
+} dictIterator;
+
+/* This is the initial size of every hash table */
+#define DICT_HT_INITIAL_SIZE 4
+
+/* ------------------------------- Macros ------------------------------------*/
+#define dictFreeEntryVal(ht, entry) \
+ if ((ht)->type->valDestructor) \
+ (ht)->type->valDestructor((ht)->privdata, (entry)->val)
+
+#define dictSetHashVal(ht, entry, _val_) do { \
+ if ((ht)->type->valDup) \
+ entry->val = (ht)->type->valDup((ht)->privdata, _val_); \
+ else \
+ entry->val = (_val_); \
+} while(0)
+
+#define dictFreeEntryKey(ht, entry) \
+ if ((ht)->type->keyDestructor) \
+ (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define dictSetHashKey(ht, entry, _key_) do { \
+ if ((ht)->type->keyDup) \
+ entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
+ else \
+ entry->key = (_key_); \
+} while(0)
+
+#define dictCompareHashKeys(ht, key1, key2) \
+ (((ht)->type->keyCompare) ? \
+ (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
+ (key1) == (key2))
+
+#define dictHashKey(ht, key) (ht)->type->hashFunction(key)
+
+#define dictGetEntryKey(he) ((he)->key)
+#define dictGetEntryVal(he) ((he)->val)
+#define dictSlots(ht) ((ht)->size)
+#define dictSize(ht) ((ht)->used)
+
+/* API */
+static unsigned int dictGenHashFunction(const unsigned char *buf, int len);
+static dict *dictCreate(dictType *type, void *privDataPtr);
+static int dictExpand(dict *ht, unsigned long size);
+static int dictAdd(dict *ht, void *key, void *val);
+static int dictReplace(dict *ht, void *key, void *val);
+static int dictDelete(dict *ht, const void *key);
+static void dictRelease(dict *ht);
+static dictEntry * dictFind(dict *ht, const void *key);
+static dictIterator *dictGetIterator(dict *ht);
+static dictEntry *dictNext(dictIterator *iter);
+static void dictReleaseIterator(dictIterator *iter);
+
+#endif /* __DICT_H */
53 node_modules/hiredis/deps/hiredis/example-ae.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include "hiredis.h"
+#include "async.h"
+#include "adapters/ae.h"
+
+/* Put event loop in the global scope, so it can be explicitly stopped */
+static aeEventLoop *loop;
+
+void getCallback(redisAsyncContext *c, void *r, void *privdata) {
+ redisReply *reply = r;
+ if (reply == NULL) return;
+ printf("argv[%s]: %s\n", (char*)privdata, reply->str);
+
+ /* Disconnect after receiving the reply to GET */
+ redisAsyncDisconnect(c);
+}
+
+void connectCallback(const redisAsyncContext *c) {
+ ((void)c);
+ printf("connected...\n");
+}
+
+void disconnectCallback(const redisAsyncContext *c, int status) {
+ if (status != REDIS_OK) {
+ printf("Error: %s\n", c->errstr);
+ }
+ printf("disconnected...\n");
+ aeStop(loop);
+}
+
+int main (int argc, char **argv) {
+ signal(SIGPIPE, SIG_IGN);
+
+ redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
+ if (c->err) {
+ /* Let *c leak for now... */
+ printf("Error: %s\n", c->errstr);
+ return 1;
+ }
+
+ loop = aeCreateEventLoop();
+ redisAeAttach(loop, c);
+ redisAsyncSetConnectCallback(c,connectCallback);
+ redisAsyncSetDisconnectCallback(c,disconnectCallback);
+ redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc-1], strlen(argv[argc-1]));
+ redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
+ aeMain(loop);
+ return 0;
+}
+
47 node_modules/hiredis/deps/hiredis/example-libev.c
@@ -0,0 +1,47 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include "hiredis.h"
+#include "async.h"
+#include "adapters/libev.h"
+
+void getCallback(redisAsyncContext *c, void *r, void *privdata) {
+ redisReply *reply = r;
+ if (reply == NULL) return;
+ printf("argv[%s]: %s\n", (char*)privdata, reply->str);
+
+ /* Disconnect after receiving the reply to GET */
+ redisAsyncDisconnect(c);
+}