vulcan 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+ }