vulcan 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (260) hide show
  1. data/lib/vulcan/cli.rb +20 -10
  2. data/lib/vulcan/version.rb +1 -1
  3. data/server/Procfile +1 -1
  4. data/server/bin/web +10 -0
  5. data/server/lib/cloudant.coffee +20 -0
  6. data/server/lib/logger.coffee +17 -0
  7. data/server/lib/on.coffee +10 -0
  8. data/server/lib/spawner.coffee +65 -0
  9. data/server/node_modules/coffee-script/CNAME +1 -0
  10. data/server/node_modules/coffee-script/LICENSE +22 -0
  11. data/server/node_modules/coffee-script/README +51 -0
  12. data/server/node_modules/coffee-script/Rakefile +78 -0
  13. data/server/node_modules/coffee-script/bin/cake +7 -0
  14. data/server/node_modules/coffee-script/bin/coffee +7 -0
  15. data/server/node_modules/coffee-script/extras/jsl.conf +44 -0
  16. data/server/node_modules/coffee-script/lib/coffee-script/browser.js +92 -0
  17. data/server/node_modules/coffee-script/lib/coffee-script/cake.js +111 -0
  18. data/server/node_modules/coffee-script/lib/coffee-script/coffee-script.js +167 -0
  19. data/server/node_modules/coffee-script/lib/coffee-script/command.js +500 -0
  20. data/server/node_modules/coffee-script/lib/coffee-script/grammar.js +606 -0
  21. data/server/node_modules/coffee-script/lib/coffee-script/helpers.js +77 -0
  22. data/server/node_modules/coffee-script/lib/coffee-script/index.js +11 -0
  23. data/server/node_modules/coffee-script/lib/coffee-script/lexer.js +788 -0
  24. data/server/node_modules/coffee-script/lib/coffee-script/nodes.js +2986 -0
  25. data/server/node_modules/coffee-script/lib/coffee-script/optparse.js +138 -0
  26. data/server/node_modules/coffee-script/lib/coffee-script/parser.js +683 -0
  27. data/server/node_modules/coffee-script/lib/coffee-script/repl.js +261 -0
  28. data/server/node_modules/coffee-script/lib/coffee-script/rewriter.js +349 -0
  29. data/server/node_modules/coffee-script/lib/coffee-script/scope.js +146 -0
  30. data/server/node_modules/coffee-script/package.json +55 -0
  31. data/server/node_modules/connect-form/History.md +0 -6
  32. data/server/node_modules/connect-form/lib/connect-form.js +2 -4
  33. data/server/node_modules/connect-form/node_modules/formidable/Readme.md +64 -36
  34. data/server/node_modules/connect-form/node_modules/formidable/lib/incoming_form.js +5 -1
  35. data/server/node_modules/connect-form/node_modules/formidable/package.json +20 -6
  36. data/server/node_modules/connect-form/node_modules/formidable/test/common.js +5 -6
  37. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/file/funkyfilename.txt +1 -0
  38. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/js/special-chars-in-filename.js +1 -1
  39. data/server/node_modules/connect-form/node_modules/formidable/test/{slow → integration}/test-fixtures.js +38 -33
  40. data/server/node_modules/connect-form/node_modules/formidable/test/legacy/simple/test-incoming-form.js +11 -0
  41. data/server/node_modules/connect-form/node_modules/formidable/test/run.js +1 -6
  42. data/server/node_modules/connect-form/node_modules/formidable/test/unit/test-incoming-form.js +63 -0
  43. data/server/node_modules/connect-form/package.json +27 -5
  44. data/server/node_modules/cradle/README.md +10 -10
  45. data/server/node_modules/cradle/lib/cradle.js +117 -523
  46. data/server/node_modules/cradle/lib/cradle/database/attachments.js +120 -0
  47. data/server/node_modules/cradle/lib/cradle/database/changes.js +56 -0
  48. data/server/node_modules/cradle/lib/cradle/database/documents.js +215 -0
  49. data/server/node_modules/cradle/lib/cradle/database/index.js +65 -0
  50. data/server/node_modules/cradle/lib/cradle/database/views.js +125 -0
  51. data/server/node_modules/cradle/node_modules/follow/LICENSE +202 -0
  52. data/server/node_modules/cradle/node_modules/follow/README.md +164 -0
  53. data/server/node_modules/cradle/node_modules/follow/Rakefile +54 -0
  54. data/server/node_modules/cradle/node_modules/follow/api.js +35 -0
  55. data/server/node_modules/cradle/node_modules/follow/browser/eventemitter2.js +453 -0
  56. data/server/node_modules/cradle/node_modules/follow/browser/export.js +78 -0
  57. data/server/node_modules/cradle/node_modules/follow/browser/index.html +14 -0
  58. data/server/node_modules/cradle/node_modules/follow/browser/jquery-1.6.1.min.js +18 -0
  59. data/server/node_modules/cradle/node_modules/follow/browser/log4js.js +46 -0
  60. data/server/node_modules/cradle/node_modules/follow/browser/main.js +92 -0
  61. data/server/node_modules/cradle/node_modules/follow/browser/querystring.js +28 -0
  62. data/server/node_modules/cradle/node_modules/follow/browser/request.jquery.js +237 -0
  63. data/server/node_modules/cradle/node_modules/follow/browser/require.js +33 -0
  64. data/server/node_modules/cradle/node_modules/follow/browser/util.js +28 -0
  65. data/server/node_modules/cradle/node_modules/follow/cli.js +101 -0
  66. data/server/node_modules/cradle/node_modules/follow/lib/feed.js +556 -0
  67. data/server/node_modules/cradle/node_modules/follow/lib/index.js +66 -0
  68. data/server/node_modules/cradle/node_modules/follow/lib/stream.js +305 -0
  69. data/server/node_modules/cradle/node_modules/follow/node_modules/request/LICENSE +55 -0
  70. data/server/node_modules/cradle/node_modules/follow/node_modules/request/README.md +285 -0
  71. data/server/node_modules/cradle/node_modules/follow/node_modules/request/main.js +618 -0
  72. data/server/node_modules/cradle/node_modules/follow/node_modules/request/mimetypes.js +146 -0
  73. data/server/node_modules/cradle/node_modules/follow/node_modules/request/oauth.js +34 -0
  74. data/server/node_modules/cradle/node_modules/follow/node_modules/request/package.json +42 -0
  75. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/googledoodle.png +0 -0
  76. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/run.sh +6 -0
  77. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/server.js +57 -0
  78. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-body.js +90 -0
  79. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-cookie.js +29 -0
  80. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-cookiejar.js +90 -0
  81. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-errors.js +30 -0
  82. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-oauth.js +109 -0
  83. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-pipes.js +167 -0
  84. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-proxy.js +39 -0
  85. data/server/node_modules/cradle/node_modules/follow/node_modules/request/tests/test-timeout.js +87 -0
  86. data/server/node_modules/cradle/node_modules/follow/node_modules/request/uuid.js +19 -0
  87. data/server/node_modules/cradle/node_modules/follow/node_modules/request/vendor/cookie/index.js +55 -0
  88. data/server/node_modules/cradle/node_modules/follow/node_modules/request/vendor/cookie/jar.js +72 -0
  89. data/server/node_modules/cradle/node_modules/follow/package.json +45 -0
  90. data/server/node_modules/cradle/node_modules/follow/test/couch.js +153 -0
  91. data/server/node_modules/cradle/node_modules/follow/test/follow.js +136 -0
  92. data/server/node_modules/cradle/node_modules/follow/test/issues.js +178 -0
  93. data/server/node_modules/cradle/node_modules/follow/test/issues/10.js +24 -0
  94. data/server/node_modules/cradle/node_modules/follow/test/stream.js +493 -0
  95. data/server/node_modules/cradle/node_modules/request/LICENSE +55 -0
  96. data/server/node_modules/cradle/node_modules/request/README.md +287 -0
  97. data/server/node_modules/cradle/node_modules/request/forever.js +103 -0
  98. data/server/node_modules/cradle/node_modules/request/main.js +913 -0
  99. data/server/node_modules/cradle/node_modules/request/mimetypes.js +152 -0
  100. data/server/node_modules/cradle/node_modules/request/oauth.js +34 -0
  101. data/server/node_modules/cradle/node_modules/request/package.json +42 -0
  102. data/server/node_modules/cradle/node_modules/request/tests/googledoodle.png +0 -0
  103. data/server/node_modules/cradle/node_modules/request/tests/run.js +38 -0
  104. data/server/node_modules/cradle/node_modules/request/tests/server.js +82 -0
  105. data/server/node_modules/cradle/node_modules/request/tests/squid.conf +77 -0
  106. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/ca.cnf +20 -0
  107. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/ca.crl +0 -0
  108. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/ca.crt +17 -0
  109. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/ca.csr +13 -0
  110. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/ca.key +18 -0
  111. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/ca.srl +1 -0
  112. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/server.cnf +19 -0
  113. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/server.crt +16 -0
  114. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/server.csr +11 -0
  115. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/server.js +28 -0
  116. data/server/node_modules/cradle/node_modules/request/tests/ssl/ca/server.key +9 -0
  117. data/server/node_modules/cradle/node_modules/request/tests/ssl/npm-ca.crt +16 -0
  118. data/server/node_modules/cradle/node_modules/request/tests/ssl/test.crt +15 -0
  119. data/server/node_modules/cradle/node_modules/request/tests/ssl/test.key +15 -0
  120. data/server/node_modules/cradle/node_modules/request/tests/test-body.js +95 -0
  121. data/server/node_modules/cradle/node_modules/request/tests/test-cookie.js +29 -0
  122. data/server/node_modules/cradle/node_modules/request/tests/test-cookiejar.js +90 -0
  123. data/server/node_modules/cradle/node_modules/request/tests/test-defaults.js +68 -0
  124. data/server/node_modules/cradle/node_modules/request/tests/test-errors.js +37 -0
  125. data/server/node_modules/cradle/node_modules/request/tests/test-headers.js +52 -0
  126. data/server/node_modules/cradle/node_modules/request/tests/test-httpModule.js +94 -0
  127. data/server/node_modules/cradle/node_modules/request/tests/test-https-strict.js +97 -0
  128. data/server/node_modules/cradle/node_modules/request/tests/test-https.js +86 -0
  129. data/server/node_modules/cradle/node_modules/request/tests/test-oauth.js +117 -0
  130. data/server/node_modules/cradle/node_modules/request/tests/test-params.js +92 -0
  131. data/server/node_modules/cradle/node_modules/request/tests/test-pipes.js +202 -0
  132. data/server/node_modules/cradle/node_modules/request/tests/test-proxy.js +39 -0
  133. data/server/node_modules/cradle/node_modules/request/tests/test-qs.js +28 -0
  134. data/server/node_modules/cradle/node_modules/request/tests/test-redirect.js +154 -0
  135. data/server/node_modules/cradle/node_modules/request/tests/test-timeout.js +87 -0
  136. data/server/node_modules/cradle/node_modules/request/tests/test-toJSON.js +14 -0
  137. data/server/node_modules/cradle/node_modules/request/tests/test-tunnel.js +61 -0
  138. data/server/node_modules/cradle/node_modules/request/tunnel.js +229 -0
  139. data/server/node_modules/cradle/node_modules/request/uuid.js +19 -0
  140. data/server/node_modules/cradle/node_modules/request/vendor/cookie/index.js +65 -0
  141. data/server/node_modules/cradle/node_modules/request/vendor/cookie/jar.js +72 -0
  142. data/server/node_modules/cradle/node_modules/vargs/package.json +33 -10
  143. data/server/node_modules/cradle/package.json +50 -12
  144. data/server/node_modules/cradle/test/cache-test.js +1 -4
  145. data/server/node_modules/cradle/test/connection-test.js +179 -0
  146. data/server/node_modules/cradle/test/database-attachment-test.js +344 -0
  147. data/server/node_modules/cradle/test/database-cache-test.js +132 -0
  148. data/server/node_modules/cradle/test/database-test.js +219 -0
  149. data/server/node_modules/cradle/test/database-view-test.js +141 -0
  150. data/server/node_modules/cradle/test/fixtures/databases.json +28 -1
  151. data/server/node_modules/cradle/test/helpers/seed.js +14 -5
  152. data/server/node_modules/cradle/test/response-test.js +1 -1
  153. data/server/node_modules/express/History.md +16 -0
  154. data/server/node_modules/express/bin/express +7 -6
  155. data/server/node_modules/express/lib-cov/application.js +510 -0
  156. data/server/node_modules/express/lib-cov/express.js +65 -0
  157. data/server/node_modules/express/lib-cov/middleware.js +54 -0
  158. data/server/node_modules/express/lib-cov/request.js +225 -0
  159. data/server/node_modules/express/lib-cov/response.js +611 -0
  160. data/server/node_modules/express/lib-cov/router/collection.js +40 -0
  161. data/server/node_modules/express/lib-cov/router/index.js +515 -0
  162. data/server/node_modules/express/lib-cov/router/methods.js +9 -0
  163. data/server/node_modules/express/lib-cov/router/route.js +68 -0
  164. data/server/node_modules/express/lib-cov/utils.js +151 -0
  165. data/server/node_modules/express/lib-cov/view.js +81 -0
  166. data/server/node_modules/express/lib/express.js +1 -1
  167. data/server/node_modules/express/lib/http.js +1 -2
  168. data/server/node_modules/express/lib/request.js +2 -2
  169. data/server/node_modules/express/lib/router/methods.js +10 -1
  170. data/server/node_modules/express/node_modules/connect/lib/connect.js +1 -1
  171. data/server/node_modules/express/node_modules/connect/lib/http.js +3 -2
  172. data/server/node_modules/express/node_modules/connect/lib/middleware/limit.js +0 -2
  173. data/server/node_modules/express/node_modules/connect/lib/middleware/session.js +1 -2
  174. data/server/node_modules/express/node_modules/connect/node_modules/formidable/Readme.md +42 -25
  175. data/server/node_modules/express/node_modules/connect/node_modules/formidable/lib/incoming_form.js +1 -0
  176. data/server/node_modules/express/node_modules/connect/node_modules/formidable/package.json +14 -3
  177. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/legacy/simple/test-incoming-form.js +11 -0
  178. data/server/node_modules/express/node_modules/connect/package.json +35 -7
  179. data/server/node_modules/express/node_modules/mime/package.json +30 -8
  180. data/server/node_modules/express/node_modules/mkdirp/README.markdown +35 -2
  181. data/server/node_modules/express/node_modules/mkdirp/examples/pow.js +1 -1
  182. data/server/node_modules/express/node_modules/mkdirp/index.js +72 -13
  183. data/server/node_modules/express/node_modules/mkdirp/package.json +39 -21
  184. data/server/node_modules/express/node_modules/mkdirp/test/chmod.js +38 -0
  185. data/server/node_modules/express/node_modules/mkdirp/test/clobber.js +37 -0
  186. data/server/node_modules/express/node_modules/mkdirp/test/perm.js +32 -0
  187. data/server/node_modules/express/node_modules/mkdirp/test/perm_sync.js +39 -0
  188. data/server/node_modules/express/node_modules/mkdirp/test/sync.js +27 -0
  189. data/server/node_modules/express/node_modules/mkdirp/test/umask.js +28 -0
  190. data/server/node_modules/express/node_modules/mkdirp/test/umask_sync.js +27 -0
  191. data/server/node_modules/express/node_modules/qs/History.md +10 -0
  192. data/server/node_modules/express/node_modules/qs/Readme.md +9 -2
  193. data/server/node_modules/express/node_modules/qs/examples.js +3 -0
  194. data/server/node_modules/express/node_modules/qs/lib/querystring.js +8 -6
  195. data/server/node_modules/express/node_modules/qs/package.json +26 -8
  196. data/server/node_modules/express/node_modules/qs/test/parse.js +13 -1
  197. data/server/node_modules/express/node_modules/qs/test/stringify.js +45 -37
  198. data/server/node_modules/express/package.json +55 -16
  199. data/server/node_modules/express/test.js +41 -0
  200. data/server/node_modules/knox/package.json +26 -4
  201. data/server/node_modules/node-uuid/package.json +40 -11
  202. data/server/node_modules/node-uuid/test/test.js +1 -1
  203. data/server/node_modules/nodemon/README.md +120 -0
  204. data/server/node_modules/nodemon/nodemon.js +518 -0
  205. data/server/node_modules/nodemon/nodemonignore.example +11 -0
  206. data/server/node_modules/nodemon/package.json +49 -0
  207. data/server/node_modules/restler/README.md +144 -94
  208. data/server/node_modules/restler/lib/multipartform.js +2 -0
  209. data/server/node_modules/restler/lib/restler.js +218 -61
  210. data/server/node_modules/restler/package.json +35 -8
  211. data/server/node_modules/restler/test/all.js +6 -1
  212. data/server/node_modules/restler/test/restler.js +624 -118
  213. data/server/package.json +14 -10
  214. data/server/web.coffee +64 -0
  215. data/server/web.js +15 -3
  216. metadata +170 -57
  217. data/server/index.js +0 -14
  218. data/server/node_modules/connect-form/LICENSE +0 -22
  219. data/server/node_modules/connect-form/index.js +0 -100
  220. data/server/node_modules/connect-form/node_modules/formidable/test/fast/test-incoming-form.js +0 -45
  221. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/no-filename/generic.http +0 -13
  222. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/osx-chrome-13.http +0 -26
  223. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http +0 -24
  224. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/osx-safari-5.http +0 -23
  225. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-chrome-12.http +0 -24
  226. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-ie-7.http +0 -22
  227. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-ie-8.http +0 -22
  228. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-safari-5.http +0 -22
  229. data/server/node_modules/connect-form/node_modules/formidable/test/fixture/multi_video.upload +0 -0
  230. data/server/node_modules/cradle/Makefile +0 -10
  231. data/server/node_modules/cradle/test/cradle-test.js +0 -650
  232. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/no-filename/generic.http +0 -13
  233. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/osx-chrome-13.http +0 -26
  234. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/osx-firefox-3.6.http +0 -24
  235. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/osx-safari-5.http +0 -23
  236. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-chrome-12.http +0 -24
  237. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-ie-7.http +0 -22
  238. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-ie-8.http +0 -22
  239. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/http/special-chars-in-filename/xp-safari-5.http +0 -22
  240. data/server/node_modules/express/node_modules/connect/node_modules/formidable/test/fixture/multi_video.upload +0 -0
  241. data/server/node_modules/express/node_modules/connect/test.js +0 -52
  242. data/server/node_modules/express/testing/foo/app.js +0 -35
  243. data/server/node_modules/express/testing/foo/package.json +0 -9
  244. data/server/node_modules/express/testing/foo/public/stylesheets/style.css +0 -8
  245. data/server/node_modules/express/testing/foo/routes/index.js +0 -10
  246. data/server/node_modules/express/testing/foo/views/index.jade +0 -2
  247. data/server/node_modules/express/testing/foo/views/layout.jade +0 -6
  248. data/server/node_modules/express/testing/index.js +0 -43
  249. data/server/node_modules/express/testing/public/test.txt +0 -2971
  250. data/server/node_modules/express/testing/views/page.html +0 -1
  251. data/server/node_modules/express/testing/views/page.jade +0 -3
  252. data/server/node_modules/express/testing/views/test.md +0 -1
  253. data/server/node_modules/express/testing/views/user/index.jade +0 -1
  254. data/server/node_modules/express/testing/views/user/list.jade +0 -1
  255. data/server/node_modules/knox/lib/knox/mime/index.js +0 -308
  256. data/server/node_modules/knox/lib/knox/mime/test.js +0 -59
  257. data/server/node_modules/node-uuid/test/benchmark-native +0 -0
  258. data/server/node_modules/on/index.js +0 -13
  259. data/server/node_modules/restler/test/test_helper.js +0 -163
  260. data/server/node_modules/spawner/index.js +0 -106
@@ -0,0 +1,33 @@
1
+ /*
2
+ RequireJS 0.26.0 Copyright (c) 2010-2011, The Dojo Foundation All Rights Reserved.
3
+ Available via the MIT or new BSD license.
4
+ see: http://github.com/jrburke/requirejs for details
5
+ */
6
+ var requirejs,require,define;
7
+ (function(){function M(a){return $.call(a)==="[object Function]"}function E(a){return $.call(a)==="[object Array]"}function V(a,c,g){for(var e in c)if(!(e in J)&&(!(e in a)||g))a[e]=c[e];return d}function R(a,c,d){a=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+a);if(d)a.originalError=d;return a}function aa(a,c,d){var e,x,j;for(e=0;j=c[e];e++){j=typeof j==="string"?{name:j}:j;x=j.location;if(d&&(!x||x.indexOf("/")!==0&&x.indexOf(":")===-1))x=d+"/"+(x||j.name);a[j.name]={name:j.name,location:x||
8
+ j.name,main:(j.main||"main").replace(fa,"").replace(ba,"")}}}function W(a,d){a.holdReady?a.holdReady(d):d?a.readyWait+=1:a.ready(!0)}function ga(a){function c(b,h){var n,o;if(b&&b.charAt(0)==="."&&h){p.pkgs[h]?h=[h]:(h=h.split("/"),h=h.slice(0,h.length-1));n=b=h.concat(b.split("/"));var a;for(o=0;a=n[o];o++)if(a===".")n.splice(o,1),o-=1;else if(a==="..")if(o===1&&(n[2]===".."||n[0]===".."))break;else o>0&&(n.splice(o-1,2),o-=2);o=p.pkgs[n=b[0]];b=b.join("/");o&&b===n+"/"+o.main&&(b=n)}return b}function g(b,
9
+ h){var n=b?b.indexOf("!"):-1,o=null,a=h?h.name:null,ha=b,g,l;n!==-1&&(o=b.substring(0,n),b=b.substring(n+1,b.length));o&&(o=c(o,a));b&&(g=o?(n=m[o])?n.normalize?n.normalize(b,function(b){return c(b,a)}):c(b,a):"__$p"+a+"@"+(b||""):c(b,a),l=E[g],l||(l=d.toModuleUrl?d.toModuleUrl(f,g,h):f.nameToUrl(g,null,h),E[g]=l));return{prefix:o,name:g,parentMap:h,url:l,originalName:ha,fullName:o?o+"!"+(g||""):g}}function e(){var b=!0,h=p.priorityWait,n,a;if(h){for(a=0;n=h[a];a++)if(!s[n]){b=!1;break}b&&delete p.priorityWait}return b}
10
+ function x(b){return function(h){b.exports=h}}function j(b,h,n){return function(){var a=[].concat(ia.call(arguments,0)),d;if(n&&M(d=a[a.length-1]))d.__requireJsBuild=!0;a.push(h);return b.apply(null,a)}}function q(b,h){var a=j(f.require,b,h);V(a,{nameToUrl:j(f.nameToUrl,b),toUrl:j(f.toUrl,b),defined:j(f.requireDefined,b),specified:j(f.requireSpecified,b),ready:d.ready,isBrowser:d.isBrowser});if(d.paths)a.paths=d.paths;return a}function v(b){var h=b.prefix,a=b.fullName;y[a]||a in m||(h&&!K[h]&&(K[h]=
11
+ void 0,(S[h]||(S[h]=[])).push(b),(t[h]||(t[h]=[])).push({onDep:function(b){if(b===h){var a,n,d,c,f,e,j=S[h];if(j)for(d=0;a=j[d];d++)if(b=a.fullName,a=g(a.originalName,a.parentMap),a=a.fullName,n=t[b]||[],c=t[a],a!==b){b in y&&(delete y[b],y[a]=!0);t[a]=c?c.concat(n):n;delete t[b];for(c=0;c<n.length;c++){e=n[c].depArray;for(f=0;f<e.length;f++)e[f]===b&&(e[f]=a)}}delete S[h]}}}),v(g(h))),f.paused.push(b))}function w(b){var h,a,c;h=b.callback;var k=b.fullName,e=[],j=b.depArray;if(h&&M(h)){if(j)for(h=
12
+ 0;h<j.length;h++)e.push(b.deps[j[h]]);if(p.catchError.define)try{a=d.execCb(k,b.callback,e,m[k])}catch(l){c=l}else a=d.execCb(k,b.callback,e,m[k]);if(k)b.cjsModule&&b.cjsModule.exports!==void 0?a=m[k]=b.cjsModule.exports:a===void 0&&b.usingExports?a=m[k]:m[k]=a}else k&&(a=m[k]=h);if(F[b.waitId])delete F[b.waitId],b.isDone=!0,f.waitCount-=1,f.waitCount===0&&(I=[]);if(c)return a=(k?g(k).url:"")||c.fileName||c.sourceURL,c=R("defineerror",'Error evaluating module "'+k+'" at location "'+a+'":\n'+c+"\nfileName:"+
13
+ a+"\nlineNumber: "+(c.lineNumber||c.line),c),c.moduleName=k,d.onError(c);if(k&&(c=t[k])){for(h=0;h<c.length;h++)c[h].onDep(k,a);delete t[k]}}function z(b,a,c,d){var b=g(b,d),k=b.name,e=b.fullName,j={},l={waitId:k||ja+Q++,depCount:0,depMax:0,prefix:b.prefix,name:k,fullName:e,deps:{},depArray:a,callback:c,onDep:function(b,a){b in l.deps||(l.deps[b]=a,l.depCount+=1,l.depCount===l.depMax&&w(l))}},i,r;if(e){if(e in m||s[e]===!0||e==="jquery"&&p.jQuery&&p.jQuery!==c().fn.jquery)return;y[e]=!0;s[e]=!0;e===
14
+ "jquery"&&c&&T(c())}for(c=0;c<a.length;c++)if(i=a[c])i=g(i,k?b:d),r=i.fullName,a[c]=r,r==="require"?l.deps[r]=q(b):r==="exports"?(l.deps[r]=m[e]={},l.usingExports=!0):r==="module"?(l.cjsModule=i=l.deps[r]={id:k,uri:k?f.nameToUrl(k,null,d):void 0,exports:m[e]},i.setExports=x(i)):r in m&&!(r in F)?l.deps[r]=m[r]:j[r]||(l.depMax+=1,v(i),(t[r]||(t[r]=[])).push(l),j[r]=!0);l.depCount===l.depMax?w(l):(F[l.waitId]=l,I.push(l),f.waitCount+=1)}function u(b){z.apply(null,b);s[b[0]]=!0}function C(b,a){if(!b.isDone){var c=
15
+ b.fullName,d=b.depArray,f,e;if(c){if(a[c])return m[c];a[c]=!0}for(e=0;e<d.length;e++)if((f=d[e])&&!b.deps[f]&&F[f])b.onDep(f,C(F[f],a));return c?m[c]:void 0}}function A(){var b=p.waitSeconds*1E3,a=b&&f.startTime+b<(new Date).getTime(),b="",c=!1,g=!1,k;if(!(f.pausedCount>0)){if(p.priorityWait)if(e())G();else return;for(k in s)if(!(k in J)&&(c=!0,!s[k]))if(a)b+=k+" ";else{g=!0;break}if(c||f.waitCount){if(a&&b)return k=R("timeout","Load timeout for modules: "+b),k.requireType="timeout",k.requireModules=
16
+ b,d.onError(k);if(g||f.scriptCount){if((B||ca)&&!X)X=setTimeout(function(){X=0;A()},50)}else{if(f.waitCount){for(H=0;b=I[H];H++)C(b,{});Y<5&&(Y+=1,A())}Y=0;d.checkReadyState()}}}}function D(b,a){var c=a.name,e=a.fullName,g;if(!(e in m||e in s))K[b]||(K[b]=m[b]),s[e]||(s[e]=!1),g=function(g){if(d.onPluginLoad)d.onPluginLoad(f,b,c,g);w({prefix:a.prefix,name:a.name,fullName:a.fullName,callback:function(){return g}});s[e]=!0},g.fromText=function(b,a){var c=N;f.loaded[b]=!1;f.scriptCount+=1;c&&(N=!1);
17
+ d.exec(a);c&&(N=!0);f.completeLoad(b)},K[b].load(c,q(a.parentMap,!0),g,p)}function L(b){b.prefix&&b.name&&b.name.indexOf("__$p")===0&&m[b.prefix]&&(b=g(b.originalName,b.parentMap));var a=b.prefix,c=b.fullName,e=f.urlFetched;!y[c]&&!s[c]&&(y[c]=!0,a?m[a]?D(a,b):(O[a]||(O[a]=[],(t[a]||(t[a]=[])).push({onDep:function(b){if(b===a){for(var c,d=O[a],b=0;b<d.length;b++)c=d[b],D(a,g(c.originalName,c.parentMap));delete O[a]}}})),O[a].push(b)):e[b.url]||(d.load(f,c,b.url),e[b.url]=!0))}var f,G,p={waitSeconds:7,
18
+ baseUrl:i.baseUrl||"./",paths:{},pkgs:{},catchError:{}},P=[],y={require:!0,exports:!0,module:!0},E={},m={},s={},F={},I=[],Q=0,t={},K={},O={},Z=0,S={};T=function(b){if(!f.jQuery&&(b=b||(typeof jQuery!=="undefined"?jQuery:null))&&!(p.jQuery&&b.fn.jquery!==p.jQuery)&&("holdReady"in b||"readyWait"in b))if(f.jQuery=b,u(["jquery",[],function(){return jQuery}]),f.scriptCount)W(b,!0),f.jQueryIncremented=!0};G=function(){var b,a,c;Z+=1;if(f.scriptCount<=0)f.scriptCount=0;for(;P.length;)if(b=P.shift(),b[0]===
19
+ null)return d.onError(R("mismatch","Mismatched anonymous define() module: "+b[b.length-1]));else u(b);if(!p.priorityWait||e())for(;f.paused.length;){c=f.paused;f.pausedCount+=c.length;f.paused=[];for(a=0;b=c[a];a++)L(b);f.startTime=(new Date).getTime();f.pausedCount-=c.length}Z===1&&A();Z-=1};f={contextName:a,config:p,defQueue:P,waiting:F,waitCount:0,specified:y,loaded:s,urlMap:E,scriptCount:0,urlFetched:{},defined:m,paused:[],pausedCount:0,plugins:K,managerCallbacks:t,makeModuleMap:g,normalize:c,
20
+ configure:function(b){var a,c,e;b.baseUrl&&b.baseUrl.charAt(b.baseUrl.length-1)!=="/"&&(b.baseUrl+="/");a=p.paths;e=p.pkgs;V(p,b,!0);if(b.paths){for(c in b.paths)c in J||(a[c]=b.paths[c]);p.paths=a}if((a=b.packagePaths)||b.packages){if(a)for(c in a)c in J||aa(e,a[c],c);b.packages&&aa(e,b.packages);p.pkgs=e}if(b.priority)c=f.requireWait,f.requireWait=!1,f.takeGlobalQueue(),G(),f.require(b.priority),G(),f.requireWait=c,p.priorityWait=b.priority;if(b.deps||b.callback)f.require(b.deps||[],b.callback);
21
+ b.ready&&d.ready(b.ready)},requireDefined:function(b,a){return g(b,a).fullName in m},requireSpecified:function(b,a){return g(b,a).fullName in y},require:function(b,c,e){if(typeof b==="string"){if(d.get)return d.get(f,b,c);c=g(b,c);b=c.fullName;return!(b in m)?d.onError(R("notloaded","Module name '"+c.fullName+"' has not been loaded yet for context: "+a)):m[b]}z(null,b,c,e);if(!f.requireWait)for(;!f.scriptCount&&f.paused.length;)f.takeGlobalQueue(),G();return f.require},takeGlobalQueue:function(){U.length&&
22
+ (ka.apply(f.defQueue,[f.defQueue.length-1,0].concat(U)),U=[])},completeLoad:function(b){var a;for(f.takeGlobalQueue();P.length;)if(a=P.shift(),a[0]===null){a[0]=b;break}else if(a[0]===b)break;else u(a),a=null;a?u(a):u([b,[],b==="jquery"&&typeof jQuery!=="undefined"?function(){return jQuery}:null]);s[b]=!0;T();d.isAsync&&(f.scriptCount-=1);G();d.isAsync||(f.scriptCount-=1)},toUrl:function(b,a){var c=b.lastIndexOf("."),d=null;c!==-1&&(d=b.substring(c,b.length),b=b.substring(0,c));return f.nameToUrl(b,
23
+ d,a)},nameToUrl:function(b,a,e){var g,j,i,m,l=f.config,b=c(b,e&&e.fullName);if(d.jsExtRegExp.test(b))a=b+(a?a:"");else{g=l.paths;j=l.pkgs;e=b.split("/");for(m=e.length;m>0;m--)if(i=e.slice(0,m).join("/"),g[i]){e.splice(0,m,g[i]);break}else if(i=j[i]){b=b===i.name?i.location+"/"+i.main:i.location;e.splice(0,m,b);break}a=e.join("/")+(a||".js");a=(a.charAt(0)==="/"||a.match(/^\w+:/)?"":l.baseUrl)+a}return l.urlArgs?a+((a.indexOf("?")===-1?"?":"&")+l.urlArgs):a}};f.jQueryCheck=T;f.resume=G;return f}function la(){var a,
24
+ c,d;if(C&&C.readyState==="interactive")return C;a=document.getElementsByTagName("script");for(c=a.length-1;c>-1&&(d=a[c]);c--)if(d.readyState==="interactive")return C=d;return null}var ma=/(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg,na=/require\(\s*["']([^'"\s]+)["']\s*\)/g,fa=/^\.\//,ba=/\.js$/,$=Object.prototype.toString,q=Array.prototype,ia=q.slice,ka=q.splice,B=!!(typeof window!=="undefined"&&navigator&&document),ca=!B&&typeof importScripts!=="undefined",oa=B&&navigator.platform==="PLAYSTATION 3"?/^complete$/:
25
+ /^(complete|loaded)$/,da=typeof opera!=="undefined"&&opera.toString()==="[object Opera]",ja="_r@@",J={},z={},U=[],C=null,Y=0,N=!1,d,q={},I,i,u,L,v,A,D,H,Q,ea,w,T,X;if(typeof define==="undefined"){if(typeof requirejs!=="undefined")if(M(requirejs))return;else q=requirejs,requirejs=void 0;typeof require!=="undefined"&&!M(require)&&(q=require,require=void 0);d=requirejs=function(a,c,d){var e="_",i;!E(a)&&typeof a!=="string"&&(i=a,E(c)?(a=c,c=d):a=[]);if(i&&i.context)e=i.context;d=z[e]||(z[e]=ga(e));i&&
26
+ d.configure(i);return d.require(a,c)};d.config=function(a){return d(a)};typeof require==="undefined"&&(require=d);d.toUrl=function(a){return z._.toUrl(a)};d.version="0.26.0";d.isArray=E;d.isFunction=M;d.mixin=V;d.jsExtRegExp=/^\/|:|\?|\.js$/;i=d.s={contexts:z,skipAsync:{},isPageLoaded:!B,readyCalls:[]};if(d.isAsync=d.isBrowser=B)if(u=i.head=document.getElementsByTagName("head")[0],L=document.getElementsByTagName("base")[0])u=i.head=L.parentNode;d.onError=function(a){throw a;};d.load=function(a,c,
27
+ g){var e=a.loaded;e[c]||(e[c]=!1);a.scriptCount+=1;d.attach(g,a,c);if(a.jQuery&&!a.jQueryIncremented)W(a.jQuery,!0),a.jQueryIncremented=!0};define=d.def=function(a,c,g){var e,i;typeof a!=="string"&&(g=c,c=a,a=null);d.isArray(c)||(g=c,c=[]);!a&&!c.length&&d.isFunction(g)&&g.length&&(g.toString().replace(ma,"").replace(na,function(a,d){c.push(d)}),c=(g.length===1?["require"]:["require","exports","module"]).concat(c));if(N&&(e=I||la()))a||(a=e.getAttribute("data-requiremodule")),i=z[e.getAttribute("data-requirecontext")];
28
+ (i?i.defQueue:U).push([a,c,g])};define.amd={multiversion:!0,plugins:!0,jQuery:!0};d.exec=function(a){return eval(a)};d.execCb=function(a,c,d,e){return c.apply(e,d)};d.onScriptLoad=function(a){var c=a.currentTarget||a.srcElement,g;if(a.type==="load"||oa.test(c.readyState))C=null,a=c.getAttribute("data-requirecontext"),g=c.getAttribute("data-requiremodule"),z[a].completeLoad(g),c.detachEvent&&!da?c.detachEvent("onreadystatechange",d.onScriptLoad):c.removeEventListener("load",d.onScriptLoad,!1)};d.attach=
29
+ function(a,c,g,e,q){var j;if(B)return e=e||d.onScriptLoad,j=c&&c.config&&c.config.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script"),j.type=q||"text/javascript",j.charset="utf-8",j.async=!i.skipAsync[a],c&&j.setAttribute("data-requirecontext",c.contextName),j.setAttribute("data-requiremodule",g),j.attachEvent&&!da?(N=!0,j.attachEvent("onreadystatechange",e)):j.addEventListener("load",e,!1),j.src=a,I=j,L?u.insertBefore(j,L):u.appendChild(j),
30
+ I=null,j;else if(ca)e=c.loaded,e[g]=!1,importScripts(a),c.completeLoad(g);return null};if(B){v=document.getElementsByTagName("script");for(H=v.length-1;H>-1&&(A=v[H]);H--){if(!u)u=A.parentNode;if(D=A.getAttribute("data-main")){if(!q.baseUrl)v=D.split("/"),A=v.pop(),v=v.length?v.join("/")+"/":"./",q.baseUrl=v,D=A.replace(ba,"");q.deps=q.deps?q.deps.concat(D):[D];break}}}i.baseUrl=q.baseUrl;d.pageLoaded=function(){if(!i.isPageLoaded){i.isPageLoaded=!0;Q&&clearInterval(Q);if(ea)document.readyState="complete";
31
+ d.callReady()}};d.checkReadyState=function(){var a=i.contexts,c;for(c in a)if(!(c in J)&&a[c].waitCount)return;i.isDone=!0;d.callReady()};d.callReady=function(){var a=i.readyCalls,c,d,e;if(i.isPageLoaded&&i.isDone){if(a.length){i.readyCalls=[];for(c=0;d=a[c];c++)d()}a=i.contexts;for(e in a)if(!(e in J)&&(c=a[e],c.jQueryIncremented))W(c.jQuery,!1),c.jQueryIncremented=!1}};d.ready=function(a){i.isPageLoaded&&i.isDone?a():i.readyCalls.push(a);return d};if(B){if(document.addEventListener){if(document.addEventListener("DOMContentLoaded",
32
+ d.pageLoaded,!1),window.addEventListener("load",d.pageLoaded,!1),!document.readyState)ea=!0,document.readyState="loading"}else window.attachEvent&&(window.attachEvent("onload",d.pageLoaded),self===self.top&&(Q=setInterval(function(){try{document.body&&(document.documentElement.doScroll("left"),d.pageLoaded())}catch(a){}},30)));document.readyState==="complete"&&d.pageLoaded()}d(q);if(d.isAsync&&typeof setTimeout!=="undefined")w=i.contexts[q.context||"_"],w.requireWait=!0,setTimeout(function(){w.requireWait=
33
+ !1;w.takeGlobalQueue();w.jQueryCheck();w.scriptCount||w.resume();d.checkReadyState()},0)}})();
@@ -0,0 +1,28 @@
1
+ define([], function() {
2
+ var exports = {};
3
+
4
+ exports.inspect = JSON.stringify;
5
+
6
+ // Copy from Node
7
+ /**
8
+ * Inherit the prototype methods from one constructor into another.
9
+ *
10
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
11
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
12
+ * during bootstrapping this function needs to be revritten using some native
13
+ * functions as prototype setup using normal JavaScript does not work as
14
+ * expected during bootstrapping (see mirror.js in r114903).
15
+ *
16
+ * @param {function} ctor Constructor function which needs to inherit the
17
+ * prototype.
18
+ * @param {function} superCtor Constructor function to inherit prototype from.
19
+ */
20
+ exports.inherits = function(ctor, superCtor) {
21
+ ctor.super_ = superCtor;
22
+ ctor.prototype = Object.create(superCtor.prototype, {
23
+ constructor: { value: ctor, enumerable: false }
24
+ });
25
+ };
26
+
27
+ return exports;
28
+ })
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ // The follow command-line interface.
3
+ //
4
+ // Copyright 2011 Iris Couch
5
+ //
6
+ // Licensed under the Apache License, Version 2.0 (the "License");
7
+ // you may not use this file except in compliance with the License.
8
+ // You may obtain a copy of the License at
9
+ //
10
+ // http://www.apache.org/licenses/LICENSE-2.0
11
+ //
12
+ // Unless required by applicable law or agreed to in writing, software
13
+ // distributed under the License is distributed on an "AS IS" BASIS,
14
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ // See the License for the specific language governing permissions and
16
+ // limitations under the License.
17
+
18
+ var lib = require('./lib')
19
+ , couch_changes = require('./api')
20
+ ;
21
+
22
+ function puts(str) {
23
+ process.stdout.write(str + "\n");
24
+ }
25
+
26
+ function main() {
27
+ var db = require.isBrowser ? (process.env.db || '/_users') : process.argv[2];
28
+ puts('Watching: ' + db);
29
+
30
+ var feed = new couch_changes.Feed();
31
+ feed.db = db;
32
+ feed.since = (process.env.since === 'now') ? 'now' : parseInt(process.env.since || '0');
33
+
34
+ feed.heartbeat = (process.env.heartbeat || '3000').replace(/s$/, '000');
35
+ feed.heartbeat = parseInt(feed.heartbeat);
36
+
37
+ if(require.isBrowser)
38
+ feed.feed = 'longpoll';
39
+ if(process.env.host)
40
+ feed.headers.host = process.env.host;
41
+ if(process.env.inactivity)
42
+ feed.inactivity_ms = parseInt(process.env.inactivity);
43
+ if(process.env.limit)
44
+ feed.limit = parseInt(process.env.limit);
45
+
46
+ feed.query_params.pid = process.pid;
47
+ feed.filter = process.env.filter || example_filter;
48
+ function example_filter(doc, req) {
49
+ // This is a local filter. It runs on the client side.
50
+ var label = 'Filter ' + (req.query.pid || '::');
51
+
52
+ if(process.env.show_doc)
53
+ console.log(label + ' doc: ' + JSON.stringify(doc));
54
+ if(process.env.show_req)
55
+ console.log(label + ' for ' + doc._id + ' req: ' + JSON.stringify(req));
56
+ return true;
57
+ }
58
+
59
+ feed.on('confirm', function() {
60
+ puts('Database confirmed: ' + db);
61
+ })
62
+
63
+ feed.on('change', function(change) {
64
+ puts('Change:' + JSON.stringify(change));
65
+ })
66
+
67
+ feed.on('timeout', function(state) {
68
+ var seconds = state.elapsed_ms / 1000;
69
+ var hb = state.heartbeat / 1000;
70
+ puts('Timeout after ' + seconds + 's inactive, heartbeat=' + hb + 's');
71
+ })
72
+
73
+ feed.on('retry', function(state) {
74
+ if(require.isBrowser)
75
+ puts('Long polling since ' + state.since);
76
+ else
77
+ puts('Retry since ' + state.since + ' after ' + state.after + 'ms');
78
+ })
79
+
80
+ feed.on('response', function() {
81
+ puts('Streaming response:');
82
+ })
83
+
84
+ feed.on('error', function(er) {
85
+ //console.error(er);
86
+ console.error('Changes error ============\n' + er.stack);
87
+ setTimeout(function() { process.exit(0) }, 100);
88
+ })
89
+
90
+ process.on('uncaughtException', function(er) {
91
+ puts('========= UNCAUGHT EXCEPTION; This is bad');
92
+ puts(er.stack);
93
+ setTimeout(function() { process.exit(1) }, 100);
94
+ })
95
+
96
+ feed.follow();
97
+ }
98
+
99
+ exports.main = main;
100
+ if(!require.isBrowser && process.argv[1] == module.filename)
101
+ main();
@@ -0,0 +1,556 @@
1
+ // Core routines for event emitters
2
+ //
3
+ // Copyright 2011 Iris Couch
4
+ //
5
+ // Licensed under the Apache License, Version 2.0 (the "License");
6
+ // you may not use this file except in compliance with the License.
7
+ // You may obtain a copy of the License at
8
+ //
9
+ // http://www.apache.org/licenses/LICENSE-2.0
10
+ //
11
+ // Unless required by applicable law or agreed to in writing, software
12
+ // distributed under the License is distributed on an "AS IS" BASIS,
13
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ // See the License for the specific language governing permissions and
15
+ // limitations under the License.
16
+
17
+ var lib = require('../lib')
18
+ , util = require('util')
19
+ , events = require('events')
20
+ , request = require('request')
21
+ , Changes = require('./stream').Changes
22
+ , querystring = require('querystring')
23
+
24
+ // Use the library timeout functions, primarily so the test suite can catch errors.
25
+ var setTimeout = lib.setTimeout
26
+ , clearTimeout = lib.clearTimeout
27
+
28
+ var DEFAULT_HEARTBEAT = 30000;
29
+ var HEARTBEAT_TIMEOUT_COEFFICIENT = 1.25; // E.g. heartbeat 1000ms would trigger a timeout after 1250ms of no heartbeat.
30
+ var DEFAULT_MAX_RETRY_SECONDS = 60 * 60;
31
+ var INITIAL_RETRY_DELAY = 1000;
32
+
33
+ var FEED_PARAMETERS = ['since', 'limit', 'feed', 'heartbeat', 'filter', 'include_docs'];
34
+
35
+ var EventEmitter = events.EventEmitter2 || events.EventEmitter;
36
+
37
+
38
+ util.inherits(Feed, EventEmitter);
39
+ function Feed (opts) {
40
+ var self = this;
41
+ EventEmitter.call(self);
42
+
43
+ self.feed = 'continuous';
44
+ self.heartbeat = DEFAULT_HEARTBEAT;
45
+ self.max_retry_seconds = DEFAULT_MAX_RETRY_SECONDS;
46
+ self.inactivity_ms = null;
47
+
48
+ self.headers = {};
49
+ self.request = {}; // Extra options for potentially future versions of request. The caller can supply them.
50
+
51
+ self.since = 0;
52
+ self.caught_up = false
53
+ self.retry_delay = INITIAL_RETRY_DELAY; // ms
54
+
55
+ self.query_params = {}; // Extra `req.query` values for filter functions
56
+
57
+ opts = opts || {};
58
+ if(typeof opts === 'string')
59
+ opts = {'db': opts};
60
+ Object.keys(opts).forEach(function(key) {
61
+ self[key] = opts[key];
62
+ })
63
+
64
+ self.pending = { request : null
65
+ , activity_at : null
66
+ };
67
+ } // Feed
68
+
69
+ Feed.prototype.start =
70
+ Feed.prototype.follow = function follow_feed() {
71
+ var self = this;
72
+
73
+ if(!self.db)
74
+ throw new Error('Database URL required');
75
+
76
+ if(self.feed !== 'continuous' && self.feed !== 'longpoll')
77
+ throw new Error('The only valid feed options are "continuous" and "longpoll"');
78
+
79
+ if(typeof self.heartbeat !== 'number')
80
+ throw new Error('Required "heartbeat" value');
81
+
82
+ self.log = lib.log4js.getLogger(self.db);
83
+ self.log.setLevel(process.env.follow_log_level || "info");
84
+
85
+ self.emit('start');
86
+ return self.confirm();
87
+ }
88
+
89
+ Feed.prototype.confirm = function confirm_feed() {
90
+ var self = this;
91
+
92
+ self.db_safe = lib.scrub_creds(self.db);
93
+
94
+ self.log.debug('Checking database: ' + self.db_safe);
95
+
96
+ var confirm_timeout = self.heartbeat * 3; // Give it time to look up the name, connect, etc.
97
+ var timeout_id = setTimeout(function() {
98
+ return self.die(new Error('Timeout confirming database: ' + self.db_safe));
99
+ }, confirm_timeout);
100
+
101
+ var headers = lib.JP(lib.JS(self.headers));
102
+ headers.accept = 'application/json';
103
+
104
+ var req = request({'uri':self.db, 'headers':headers}, db_response)
105
+ self.emit('confirm_request', req)
106
+
107
+ function db_response(er, resp, body) {
108
+ clearTimeout(timeout_id);
109
+
110
+ if(er)
111
+ return self.die(er);
112
+
113
+ var db;
114
+ try {
115
+ db = JSON.parse(body)
116
+ } catch(json_er) {
117
+ return self.emit('error', json_er)
118
+ }
119
+
120
+ if(!db.db_name || !db.instance_start_time)
121
+ return self.emit('error', new Error('Bad DB response: ' + body));
122
+
123
+ self.original_db_seq = db.update_seq
124
+ self.log.debug('Confirmed db: ' + self.db_safe);
125
+ self.emit('confirm', db);
126
+
127
+ if(self.since == 'now') {
128
+ self.log.debug('Query since "now" is the same as query since -1')
129
+ self.since = -1
130
+ }
131
+
132
+ if(self.since < 0) {
133
+ self.log.debug('Query since '+self.since+' will start at ' + (db.update_seq + self.since + 1))
134
+ self.since = db.update_seq + self.since + 1
135
+ }
136
+
137
+ // If the next change would come after the current update_seq, just fake a catchup event now.
138
+ if(self.original_db_seq == self.since) {
139
+ self.caught_up = true
140
+ self.emit('catchup', db.update_seq)
141
+ }
142
+
143
+ return self.query();
144
+ }
145
+ }
146
+
147
+ Feed.prototype.query = function query_feed() {
148
+ var self = this;
149
+
150
+ var query_params = JSON.parse(JSON.stringify(self.query_params));
151
+
152
+ FEED_PARAMETERS.forEach(function(key) {
153
+ if(key in self)
154
+ query_params[key] = self[key];
155
+ })
156
+
157
+ if(typeof query_params.filter !== 'string')
158
+ delete query_params.filter;
159
+
160
+ if(typeof self.filter === 'function' && !query_params.include_docs) {
161
+ self.log.debug('Enabling include_docs for client-side filter');
162
+ query_params.include_docs = true;
163
+ }
164
+
165
+ // Limit the response size for longpoll.
166
+ var poll_size = 100;
167
+ if(query_params.feed == 'longpoll' && (!query_params.limit || query_params.limit > poll_size))
168
+ query_params.limit = poll_size;
169
+
170
+ var feed_url = self.db + '/_changes?' + querystring.stringify(query_params);
171
+
172
+ self.headers.accept = self.headers.accept || 'application/json';
173
+ var req = { method : 'GET'
174
+ , uri : feed_url
175
+ , headers: self.headers
176
+ , encoding: 'utf-8'
177
+ , onResponse: on_feed_response
178
+ }
179
+
180
+ req.changes_query = query_params;
181
+ Object.keys(self.request).forEach(function(key) {
182
+ req[key] = self.request[key];
183
+ })
184
+
185
+ var now = new Date
186
+ , feed_ts = lib.JDUP(now)
187
+ , feed_id = process.env.follow_debug ? feed_ts.match(/\.(\d\d\d)Z$/)[1] : feed_ts
188
+
189
+ self.log.debug('Feed query ' + feed_id + ': ' + lib.scrub_creds(feed_url))
190
+ var feed_request = request(req)
191
+ feed_request.on('response', function() {
192
+ self.log.debug('Remove feed from agent pool: ' + feed_id)
193
+ feed_request.req.socket.emit('agentRemove')
194
+ })
195
+
196
+ // The response headers must arrive within one heartbeat.
197
+ var response_timer = setTimeout(response_timed_out, self.heartbeat)
198
+ , timed_out = false
199
+
200
+ return self.emit('query', feed_request)
201
+
202
+ function response_timed_out() {
203
+ self.log.debug('Feed response timed out: ' + feed_id)
204
+ timed_out = true
205
+ return self.retry()
206
+ }
207
+
208
+ function on_feed_response(er, resp, body) {
209
+ clearTimeout(response_timer)
210
+
211
+ if((resp !== undefined && resp.body) || body)
212
+ return self.die(new Error('Cannot handle a body in the feed response: ' + lib.JS(resp.body || body)))
213
+
214
+ if(timed_out) {
215
+ self.log.debug('Ignoring late response: ' + feed_id);
216
+ return destroy_response(resp);
217
+ }
218
+
219
+ if(er) {
220
+ self.log.debug('Request error ' + feed_id + ': ' + er.stack);
221
+ destroy_response(resp);
222
+ return self.retry();
223
+ }
224
+
225
+ if(resp.statusCode !== 200) {
226
+ self.log.debug('Bad changes response ' + feed_id + ': ' + resp.statusCode);
227
+ destroy_response(resp);
228
+ return self.retry();
229
+ }
230
+
231
+ self.log.debug('Good response: ' + feed_id);
232
+ self.retry_delay = INITIAL_RETRY_DELAY;
233
+
234
+ self.emit('response', resp);
235
+
236
+ var changes_stream = new Changes
237
+ changes_stream.log = lib.log4js.getLogger('stream ' + self.db)
238
+ changes_stream.log.setLevel(self.log.level.levelStr)
239
+ changes_stream.feed = self.feed
240
+ feed_request.pipe(changes_stream)
241
+
242
+ changes_stream.created_at = now
243
+ changes_stream.id = function() { return feed_id }
244
+ return self.prep(changes_stream)
245
+ }
246
+ }
247
+
248
+ Feed.prototype.prep = function prep_request(changes_stream) {
249
+ var self = this;
250
+
251
+ var now = new Date;
252
+ self.pending.request = changes_stream;
253
+ self.pending.activity_at = now;
254
+ self.pending.wait_timer = null;
255
+
256
+ // The inactivity timer is for time between *changes*, or time between the
257
+ // initial connection and the first change. Therefore it goes here.
258
+ self.change_at = now;
259
+ if(self.inactivity_ms) {
260
+ clearTimeout(self.inactivity_timer);
261
+ self.inactivity_timer = setTimeout(function() { self.on_inactivity() }, self.inactivity_ms);
262
+ }
263
+
264
+ changes_stream.on('heartbeat', handler_for('heartbeat'))
265
+ changes_stream.on('error', handler_for('error'))
266
+ changes_stream.on('data', handler_for('data'))
267
+ changes_stream.on('end', handler_for('end'))
268
+
269
+ return self.wait();
270
+
271
+ function handler_for(ev) {
272
+ var name = 'on_couch_' + ev;
273
+ var inner_handler = self[name];
274
+
275
+ return handle_confirmed_req_event;
276
+ function handle_confirmed_req_event() {
277
+ if(self.pending.request === changes_stream)
278
+ return inner_handler.apply(self, arguments);
279
+
280
+ if(!changes_stream.created_at)
281
+ return self.die(new Error("Received data from unknown request")); // Pretty sure this is impossible.
282
+
283
+ var s_to_now = (new Date() - changes_stream.created_at) / 1000;
284
+ var s_to_req = '[no req]';
285
+ if(self.pending.request)
286
+ s_to_req = (self.pending.request.created_at - changes_stream.created_at) / 1000;
287
+
288
+ var msg = ': ' + changes_stream.id() + ' to_req=' + s_to_req + 's, to_now=' + s_to_now + 's';
289
+
290
+ if(ev == 'end' || ev == 'data' || ev == 'heartbeat') {
291
+ self.log.debug('Old "' + ev + '": ' + changes_stream.id())
292
+ return destroy_req(changes_stream)
293
+ }
294
+
295
+ self.log.warn('Old "'+ev+'"' + msg);
296
+ }
297
+ }
298
+ }
299
+
300
+ Feed.prototype.wait = function wait_for_event() {
301
+ var self = this;
302
+ self.emit('wait');
303
+
304
+ if(self.pending.wait_timer)
305
+ return self.die(new Error('wait() called but there is already a wait_timer: ' + self.pending.wait_timer));
306
+
307
+ var timeout_ms = self.heartbeat * HEARTBEAT_TIMEOUT_COEFFICIENT;
308
+ var req_id = self.pending.request && self.pending.request.id()
309
+ var msg = 'Req ' + req_id + ' timeout=' + timeout_ms;
310
+ if(self.inactivity_ms)
311
+ msg += ', inactivity=' + self.inactivity_ms;
312
+ msg += ': ' + self.db_safe;
313
+
314
+ self.log.debug(msg);
315
+ self.pending.wait_timer = setTimeout(function() { self.on_timeout() }, timeout_ms);
316
+ }
317
+
318
+ Feed.prototype.got_activity = function() {
319
+ var self = this
320
+
321
+ if(! self.pending.wait_timer)
322
+ return self.die(new Error('Cannot find wait timer'))
323
+
324
+ clearTimeout(self.pending.wait_timer)
325
+ self.pending.wait_timer = null
326
+ self.pending.activity_at = new Date
327
+ }
328
+
329
+ Feed.prototype.on_couch_heartbeat = function on_couch_heartbeat() {
330
+ var self = this
331
+
332
+ self.got_activity()
333
+ if(self.dead)
334
+ return self.log.debug('Skip heartbeat processing for dead feed')
335
+
336
+ self.emit('heartbeat')
337
+
338
+ if(self.dead)
339
+ return self.log.debug('No wait: heartbeat listener stopped this feed')
340
+ self.wait()
341
+ }
342
+
343
+ Feed.prototype.on_couch_data = function on_couch_data(change) {
344
+ var self = this;
345
+ self.log.debug('Data from ' + self.pending.request.id());
346
+
347
+ self.got_activity()
348
+ if(self.dead)
349
+ return self.log.debug('Skip data processing for dead feed')
350
+
351
+ // The changes stream guarantees that this data is valid JSON.
352
+ change = JSON.parse(change)
353
+
354
+ //self.log.debug('Object:\n' + util.inspect(change));
355
+ if('last_seq' in change) {
356
+ self.log.warn('Stopping upon receiving a final message: ' + JSON.stringify(change))
357
+ var del_er = new Error('Database deleted after change: ' + change.last_seq)
358
+ del_er.deleted = true
359
+ del_er.last_seq = change.last_seq
360
+ return self.die(del_er)
361
+ }
362
+
363
+ if(!change.seq)
364
+ return self.die(new Error('Change has no .seq field: ' + JSON.stringify(change)))
365
+
366
+ self.on_change(change)
367
+
368
+ // on_change() might work its way all the way to a "change" event, and the listener
369
+ // might call .stop(), which means among other things that no more events are desired.
370
+ // The die() code sets a self.dead flag to indicate this.
371
+ if(self.dead)
372
+ return self.log.debug('No wait: change listener stopped this feed')
373
+ self.wait()
374
+ }
375
+
376
+ Feed.prototype.on_timeout = function on_timeout() {
377
+ var self = this;
378
+ self.log.debug('Timeout')
379
+
380
+ var now = new Date;
381
+ var elapsed_ms = now - self.pending.activity_at;
382
+
383
+ self.emit('timeout', {elapsed_ms:elapsed_ms, heartbeat:self.heartbeat, id:self.pending.request.id()});
384
+
385
+ /*
386
+ var msg = ' for timeout after ' + elapsed_ms + 'ms; heartbeat=' + self.heartbeat;
387
+ if(!self.pending.request.id)
388
+ self.log.warn('Closing req (no id) ' + msg + ' req=' + util.inspect(self.pending.request));
389
+ else
390
+ self.log.warn('Closing req ' + self.pending.request.id() + msg);
391
+ */
392
+
393
+ destroy_req(self.pending.request);
394
+ self.retry()
395
+ }
396
+
397
+ Feed.prototype.retry = function retry() {
398
+ var self = this;
399
+
400
+ clearTimeout(self.pending.wait_timer);
401
+ self.pending.wait_timer = null;
402
+
403
+ self.log.debug('Retry since=' + self.since + ' after ' + self.retry_delay + 'ms ')
404
+ self.emit('retry', {since:self.since, after:self.retry_delay, db:self.db_safe});
405
+
406
+ self.retry_timer = setTimeout(function() { self.query() }, self.retry_delay);
407
+
408
+ var max_retry_ms = self.max_retry_seconds * 1000;
409
+ self.retry_delay *= 2;
410
+ if(self.retry_delay > max_retry_ms)
411
+ self.retry_delay = max_retry_ms;
412
+ }
413
+
414
+ Feed.prototype.on_couch_end = function on_couch_end() {
415
+ var self = this;
416
+
417
+ self.log.debug('Changes feed ended ' + self.pending.request.id());
418
+ self.pending.request = null;
419
+ return self.retry();
420
+ }
421
+
422
+ Feed.prototype.on_couch_error = function on_couch_error(er) {
423
+ var self = this;
424
+
425
+ self.log.debug('Changes query eror: ' + lib.JS(er.stack));
426
+ return self.retry();
427
+ }
428
+
429
+ Feed.prototype.stop = function(val) {
430
+ var self = this
431
+ self.log.debug('Stop')
432
+
433
+ // Die with no errors.
434
+ self.die()
435
+ self.emit('stop', val);
436
+ }
437
+
438
+ Feed.prototype.die = function(er) {
439
+ var self = this;
440
+
441
+ if(er)
442
+ self.log.fatal('Fatal error: ' + er.stack);
443
+
444
+ // Warn code executing later that death has occured.
445
+ self.dead = true
446
+
447
+ clearTimeout(self.retry_timer)
448
+ clearTimeout(self.inactivity_timer)
449
+ clearTimeout(self.pending.wait_timer)
450
+
451
+ self.inactivity_timer = null
452
+ self.pending.wait_timer = null
453
+
454
+ var req = self.pending.request;
455
+ self.pending.request = null;
456
+ if(req) {
457
+ self.log.debug('Destroying req ' + req.id());
458
+ destroy_req(req);
459
+ }
460
+
461
+ if(er)
462
+ self.emit('error', er);
463
+ }
464
+
465
+ Feed.prototype.on_change = function on_change(change) {
466
+ var self = this;
467
+
468
+ if(!change.seq)
469
+ return self.die(new Error('No seq value in change: ' + lib.JS(change)));
470
+
471
+ if(change.seq <= self.since) {
472
+ self.log.debug('Bad seq value ' + change.seq + ' since=' + self.since);
473
+ return destroy_req(self.pending.request);
474
+ }
475
+
476
+ if(!self.caught_up && change.seq >= self.original_db_seq) {
477
+ self.caught_up = true
478
+ self.emit('catchup', change.seq)
479
+ }
480
+
481
+ if(typeof self.filter !== 'function')
482
+ return self.on_good_change(change);
483
+
484
+ if(!change.doc)
485
+ return self.die(new Error('Internal filter needs .doc in change ' + change.seq));
486
+
487
+ // Don't let the filter mutate the real data.
488
+ var doc = lib.JDUP(change.doc);
489
+ var req = lib.JDUP({'query': self.pending.request.changes_query});
490
+
491
+ var result = false;
492
+ try {
493
+ result = self.filter.apply(null, [doc, req]);
494
+ } catch (er) {
495
+ self.log.debug('Filter error', er);
496
+ }
497
+
498
+ result = (result && true) || false;
499
+ if(result) {
500
+ self.log.debug('Builtin filter PASS for change: ' + change.seq);
501
+ return self.on_good_change(change);
502
+ } else
503
+ self.log.debug('Builtin filter FAIL for change: ' + change.seq);
504
+ }
505
+
506
+ Feed.prototype.on_good_change = function on_good_change(change) {
507
+ var self = this;
508
+
509
+ if(self.inactivity_ms && !self.inactivity_timer)
510
+ return self.die(new Error('Cannot find inactivity timer during change'));
511
+
512
+ clearTimeout(self.inactivity_timer);
513
+ self.inactivity_timer = null;
514
+ if(self.inactivity_ms)
515
+ self.inactivity_timer = setTimeout(function() { self.on_inactivity() }, self.inactivity_ms);
516
+
517
+ self.change_at = new Date;
518
+ self.since = change.seq;
519
+ self.emit('change', change);
520
+ }
521
+
522
+ Feed.prototype.on_inactivity = function on_inactivity() {
523
+ var self = this;
524
+ var now = new Date;
525
+ var elapsed_ms = now - self.change_at;
526
+ var elapsed_s = elapsed_ms / 1000;
527
+
528
+ return self.die(new Error('Req ' + self.pending.request.id() + ' made no changes for ' + elapsed_s + 's'));
529
+ }
530
+
531
+ module.exports = { "Feed" : Feed
532
+ };
533
+
534
+
535
+ /*
536
+ * Utilities
537
+ */
538
+
539
+ function destroy_req(req) {
540
+ if(req)
541
+ destroy_response(req.response)
542
+
543
+ if(req && typeof req.destroy == 'function')
544
+ req.destroy()
545
+ }
546
+
547
+ function destroy_response(response) {
548
+ if(!response)
549
+ return;
550
+
551
+ if(typeof response.abort === 'function')
552
+ response.abort();
553
+
554
+ if(response.connection)
555
+ response.connection.destroy();
556
+ }