summaryrefslogtreecommitdiffstats
path: root/node_modules/kareem
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/kareem')
-rw-r--r--node_modules/kareem/.travis.yml12
-rw-r--r--node_modules/kareem/CHANGELOG.md790
-rw-r--r--node_modules/kareem/LICENSE202
-rw-r--r--node_modules/kareem/Makefile5
-rw-r--r--node_modules/kareem/README.md428
-rw-r--r--node_modules/kareem/docs.js37
-rw-r--r--node_modules/kareem/gulpfile.js18
-rw-r--r--node_modules/kareem/index.js511
-rw-r--r--node_modules/kareem/package.json53
-rw-r--r--node_modules/kareem/test/examples.test.js379
-rw-r--r--node_modules/kareem/test/misc.test.js71
-rw-r--r--node_modules/kareem/test/post.test.js198
-rw-r--r--node_modules/kareem/test/pre.test.js320
-rw-r--r--node_modules/kareem/test/wrap.test.js342
14 files changed, 3366 insertions, 0 deletions
diff --git a/node_modules/kareem/.travis.yml b/node_modules/kareem/.travis.yml
new file mode 100644
index 0000000..0a388b9
--- /dev/null
+++ b/node_modules/kareem/.travis.yml
@@ -0,0 +1,12 @@
+language: node_js
+node_js:
+ - "12"
+ - "10"
+ - "9"
+ - "8"
+ - "7"
+ - "6"
+ - "5"
+ - "4"
+script: "npm run-script test-travis"
+after_script: "npm install coveralls@2.10.0 && cat ./coverage/lcov.info | coveralls"
diff --git a/node_modules/kareem/CHANGELOG.md b/node_modules/kareem/CHANGELOG.md
new file mode 100644
index 0000000..aa011f4
--- /dev/null
+++ b/node_modules/kareem/CHANGELOG.md
@@ -0,0 +1,790 @@
+# Change Log
+
+All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+
+<a name="2.3.0"></a>
+## 2.3.0 (2018-09-24)
+
+* chore(release): 2.2.3 ([c8f2695](https://github.com/vkarpov15/kareem/commit/c8f2695))
+* chore(release): 2.2.4 ([a377a4f](https://github.com/vkarpov15/kareem/commit/a377a4f))
+* chore(release): 2.2.5 ([5a495e3](https://github.com/vkarpov15/kareem/commit/5a495e3))
+* fix(filter): copy async pres correctly with `filter()` ([1b1ed8a](https://github.com/vkarpov15/kareem/commit/1b1ed8a)), closes [Automattic/mongoose#3054](https://github.com/Automattic/mongoose/issues/3054)
+* feat: add filter() function ([1f641f4](https://github.com/vkarpov15/kareem/commit/1f641f4))
+* feat: support storing options on pre and post hooks ([59220b9](https://github.com/vkarpov15/kareem/commit/59220b9))
+
+
+
+<a name="2.2.3"></a>
+## <small>2.2.3 (2018-09-10)</small>
+
+* chore: release 2.2.3 ([af653a3](https://github.com/vkarpov15/kareem/commit/af653a3))
+
+
+
+<a name="2.2.2"></a>
+## <small>2.2.2 (2018-09-10)</small>
+
+* chore: release 2.2.2 ([3f0144d](https://github.com/vkarpov15/kareem/commit/3f0144d))
+* fix: allow merge() to not clone ([e628d65](https://github.com/vkarpov15/kareem/commit/e628d65))
+
+
+
+<a name="2.2.1"></a>
+## <small>2.2.1 (2018-06-05)</small>
+
+* chore: release 2.2.1 ([4625a64](https://github.com/vkarpov15/kareem/commit/4625a64))
+* chore: remove lockfile from git ([7f3e4e6](https://github.com/vkarpov15/kareem/commit/7f3e4e6))
+* fix: handle numAsync correctly when merging ([fef8e7e](https://github.com/vkarpov15/kareem/commit/fef8e7e))
+* test: repro issue with not copying numAsync ([952d9db](https://github.com/vkarpov15/kareem/commit/952d9db))
+
+
+
+<a name="2.2.0"></a>
+## 2.2.0 (2018-06-05)
+
+* chore: release 2.2.0 ([ff9ad03](https://github.com/vkarpov15/kareem/commit/ff9ad03))
+* fix: use maps instead of objects for _pres and _posts so `toString()` doesn't get reported as having ([55df303](https://github.com/vkarpov15/kareem/commit/55df303)), closes [Automattic/mongoose#6538](https://github.com/Automattic/mongoose/issues/6538)
+
+
+
+<a name="2.1.0"></a>
+## 2.1.0 (2018-05-16)
+
+* chore: release 2.1.0 ([ba5f1bc](https://github.com/vkarpov15/kareem/commit/ba5f1bc))
+* feat: add option to check wrapped function return value for promises ([c9d7dd1](https://github.com/vkarpov15/kareem/commit/c9d7dd1))
+* refactor: use const in wrap() ([0fc21f9](https://github.com/vkarpov15/kareem/commit/0fc21f9))
+
+
+
+<a name="2.0.7"></a>
+## <small>2.0.7 (2018-04-28)</small>
+
+* chore: release 2.0.7 ([0bf91e6](https://github.com/vkarpov15/kareem/commit/0bf91e6))
+* feat: add `hasHooks()` ([225f18d](https://github.com/vkarpov15/kareem/commit/225f18d)), closes [Automattic/mongoose#6385](https://github.com/Automattic/mongoose/issues/6385)
+
+
+
+<a name="2.0.6"></a>
+## <small>2.0.6 (2018-03-22)</small>
+
+* chore: release 2.0.6 ([f3d406b](https://github.com/vkarpov15/kareem/commit/f3d406b))
+* fix(wrap): ensure fast path still wraps function in `nextTick()` for chaining ([7000494](https://github.com/vkarpov15/kareem/commit/7000494)), closes [Automattic/mongoose#6250](https://github.com/Automattic/mongoose/issues/6250) [dsanel/mongoose-delete#36](https://github.com/dsanel/mongoose-delete/issues/36)
+
+
+
+<a name="2.0.5"></a>
+## <small>2.0.5 (2018-02-22)</small>
+
+* chore: release 2.0.5 ([3286612](https://github.com/vkarpov15/kareem/commit/3286612))
+* perf(createWrapper): don't create wrapper if there are no hooks ([5afc5b9](https://github.com/vkarpov15/kareem/commit/5afc5b9)), closes [Automattic/mongoose#6126](https://github.com/Automattic/mongoose/issues/6126)
+
+
+
+<a name="2.0.4"></a>
+## <small>2.0.4 (2018-02-08)</small>
+
+* chore: release 2.0.4 ([2ab0293](https://github.com/vkarpov15/kareem/commit/2ab0293))
+
+
+
+<a name="2.0.3"></a>
+## <small>2.0.3 (2018-02-01)</small>
+
+* chore: release 2.0.3 ([3c1abe5](https://github.com/vkarpov15/kareem/commit/3c1abe5))
+* fix: use process.nextTick() re: Automattic/mongoose#6074 ([e5bfe33](https://github.com/vkarpov15/kareem/commit/e5bfe33)), closes [Automattic/mongoose#6074](https://github.com/Automattic/mongoose/issues/6074)
+
+
+
+<a name="2.0.2"></a>
+## <small>2.0.2 (2018-01-24)</small>
+
+* chore: fix license ([a9d755c](https://github.com/vkarpov15/kareem/commit/a9d755c)), closes [#10](https://github.com/vkarpov15/kareem/issues/10)
+* chore: release 2.0.2 ([fe87ab6](https://github.com/vkarpov15/kareem/commit/fe87ab6))
+
+
+
+<a name="2.0.1"></a>
+## <small>2.0.1 (2018-01-09)</small>
+
+* chore: release 2.0.1 with lockfile bump ([09c44fb](https://github.com/vkarpov15/kareem/commit/09c44fb))
+
+
+
+<a name="2.0.0"></a>
+## 2.0.0 (2018-01-09)
+
+* chore: bump marked re: security ([cc564a9](https://github.com/vkarpov15/kareem/commit/cc564a9))
+* chore: release 2.0.0 ([f511d1c](https://github.com/vkarpov15/kareem/commit/f511d1c))
+
+
+
+<a name="2.0.0-rc5"></a>
+## 2.0.0-rc5 (2017-12-23)
+
+* chore: fix build on node 4+5 ([6dac5a4](https://github.com/vkarpov15/kareem/commit/6dac5a4))
+* chore: fix built on node 4 + 5 again ([434ef0a](https://github.com/vkarpov15/kareem/commit/434ef0a))
+* chore: release 2.0.0-rc5 ([25a32ee](https://github.com/vkarpov15/kareem/commit/25a32ee))
+
+
+
+<a name="2.0.0-rc4"></a>
+## 2.0.0-rc4 (2017-12-22)
+
+* chore: release 2.0.0-rc4 ([49fc083](https://github.com/vkarpov15/kareem/commit/49fc083))
+* BREAKING CHANGE: deduplicate when merging hooks re: Automattic/mongoose#2945 ([d458573](https://github.com/vkarpov15/kareem/commit/d458573)), closes [Automattic/mongoose#2945](https://github.com/Automattic/mongoose/issues/2945)
+
+
+
+<a name="2.0.0-rc3"></a>
+## 2.0.0-rc3 (2017-12-22)
+
+* chore: release 2.0.0-rc3 ([adaaa00](https://github.com/vkarpov15/kareem/commit/adaaa00))
+* feat: support returning promises from middleware functions ([05b4480](https://github.com/vkarpov15/kareem/commit/05b4480)), closes [Automattic/mongoose#3779](https://github.com/Automattic/mongoose/issues/3779)
+
+
+
+<a name="2.0.0-rc2"></a>
+## 2.0.0-rc2 (2017-12-21)
+
+* chore: release 2.0.0-rc2 ([76325fa](https://github.com/vkarpov15/kareem/commit/76325fa))
+* fix: ensure next() and done() run in next tick ([6c20684](https://github.com/vkarpov15/kareem/commit/6c20684))
+
+
+
+<a name="2.0.0-rc1"></a>
+## 2.0.0-rc1 (2017-12-21)
+
+* chore: improve test coverage re: Automattic/mongoose#3232 ([7b45cf0](https://github.com/vkarpov15/kareem/commit/7b45cf0)), closes [Automattic/mongoose#3232](https://github.com/Automattic/mongoose/issues/3232)
+* chore: release 2.0.0-rc1 ([9b83f52](https://github.com/vkarpov15/kareem/commit/9b83f52))
+* BREAKING CHANGE: report sync exceptions as errors, only allow calling next() and done() once ([674adcc](https://github.com/vkarpov15/kareem/commit/674adcc)), closes [Automattic/mongoose#3483](https://github.com/Automattic/mongoose/issues/3483)
+
+
+
+<a name="2.0.0-rc0"></a>
+## 2.0.0-rc0 (2017-12-17)
+
+* chore: release 2.0.0-rc0 ([16b44b5](https://github.com/vkarpov15/kareem/commit/16b44b5))
+* BREAKING CHANGE: drop support for node < 4 ([9cbb8c7](https://github.com/vkarpov15/kareem/commit/9cbb8c7))
+* BREAKING CHANGE: remove useLegacyPost and add several new features ([6dd8531](https://github.com/vkarpov15/kareem/commit/6dd8531)), closes [Automattic/mongoose#3232](https://github.com/Automattic/mongoose/issues/3232)
+
+
+
+<a name="1.5.0"></a>
+## 1.5.0 (2017-07-20)
+
+* chore: release 1.5.0 ([9c491a0](https://github.com/vkarpov15/kareem/commit/9c491a0))
+* fix: improve post error handlers results ([9928dd5](https://github.com/vkarpov15/kareem/commit/9928dd5)), closes [Automattic/mongoose#5466](https://github.com/Automattic/mongoose/issues/5466)
+
+
+
+<a name="1.4.2"></a>
+## <small>1.4.2 (2017-07-06)</small>
+
+* chore: release 1.4.2 ([8d14ac5](https://github.com/vkarpov15/kareem/commit/8d14ac5))
+* fix: correct args re: Automattic/mongoose#5405 ([3f28ae6](https://github.com/vkarpov15/kareem/commit/3f28ae6)), closes [Automattic/mongoose#5405](https://github.com/Automattic/mongoose/issues/5405)
+
+
+
+<a name="1.4.1"></a>
+## <small>1.4.1 (2017-04-25)</small>
+
+* chore: release 1.4.1 ([5ecf0c2](https://github.com/vkarpov15/kareem/commit/5ecf0c2))
+* fix: handle numAsyncPres with clone() ([c72e857](https://github.com/vkarpov15/kareem/commit/c72e857)), closes [#8](https://github.com/vkarpov15/kareem/issues/8)
+* test: repro #8 ([9b4d6b2](https://github.com/vkarpov15/kareem/commit/9b4d6b2)), closes [#8](https://github.com/vkarpov15/kareem/issues/8)
+
+
+
+<a name="1.4.0"></a>
+## 1.4.0 (2017-04-19)
+
+* chore: release 1.4.0 ([101c5f5](https://github.com/vkarpov15/kareem/commit/101c5f5))
+* feat: add merge() function ([285325e](https://github.com/vkarpov15/kareem/commit/285325e))
+
+
+
+<a name="1.3.0"></a>
+## 1.3.0 (2017-03-26)
+
+* chore: release 1.3.0 ([f3a9e50](https://github.com/vkarpov15/kareem/commit/f3a9e50))
+* feat: pass function args to execPre ([4dd466d](https://github.com/vkarpov15/kareem/commit/4dd466d))
+
+
+
+<a name="1.2.1"></a>
+## <small>1.2.1 (2017-02-03)</small>
+
+* chore: release 1.2.1 ([d97081f](https://github.com/vkarpov15/kareem/commit/d97081f))
+* fix: filter out _kareemIgnored args for error handlers re: Automattic/mongoose#4925 ([ddc7aeb](https://github.com/vkarpov15/kareem/commit/ddc7aeb)), closes [Automattic/mongoose#4925](https://github.com/Automattic/mongoose/issues/4925)
+* fix: make error handlers handle errors in pre hooks ([af38033](https://github.com/vkarpov15/kareem/commit/af38033)), closes [Automattic/mongoose#4927](https://github.com/Automattic/mongoose/issues/4927)
+
+
+
+<a name="1.2.0"></a>
+## 1.2.0 (2017-01-02)
+
+* chore: release 1.2.0 ([033225c](https://github.com/vkarpov15/kareem/commit/033225c))
+* chore: upgrade deps ([f9e9a09](https://github.com/vkarpov15/kareem/commit/f9e9a09))
+* feat: add _kareemIgnore re: Automattic/mongoose#4836 ([7957771](https://github.com/vkarpov15/kareem/commit/7957771)), closes [Automattic/mongoose#4836](https://github.com/Automattic/mongoose/issues/4836)
+
+
+
+<a name="1.1.5"></a>
+## <small>1.1.5 (2016-12-13)</small>
+
+* chore: release 1.1.5 ([1a9f684](https://github.com/vkarpov15/kareem/commit/1a9f684))
+* fix: correct field name ([04a0e9d](https://github.com/vkarpov15/kareem/commit/04a0e9d))
+
+
+
+<a name="1.1.4"></a>
+## <small>1.1.4 (2016-12-09)</small>
+
+* chore: release 1.1.4 ([ece401c](https://github.com/vkarpov15/kareem/commit/ece401c))
+* chore: run tests on node 6 ([e0cb1cb](https://github.com/vkarpov15/kareem/commit/e0cb1cb))
+* fix: only copy own properties in clone() ([dfe28ce](https://github.com/vkarpov15/kareem/commit/dfe28ce)), closes [#7](https://github.com/vkarpov15/kareem/issues/7)
+
+
+
+<a name="1.1.3"></a>
+## <small>1.1.3 (2016-06-27)</small>
+
+* chore: release 1.1.3 ([87171c8](https://github.com/vkarpov15/kareem/commit/87171c8))
+* fix: couple more issues with arg processing ([c65f523](https://github.com/vkarpov15/kareem/commit/c65f523))
+
+
+
+<a name="1.1.2"></a>
+## <small>1.1.2 (2016-06-27)</small>
+
+* chore: release 1.1.2 ([8e102b6](https://github.com/vkarpov15/kareem/commit/8e102b6))
+* fix: add early return ([4feda4e](https://github.com/vkarpov15/kareem/commit/4feda4e))
+
+
+
+<a name="1.1.1"></a>
+## <small>1.1.1 (2016-06-27)</small>
+
+* chore: release 1.1.1 ([8bb3050](https://github.com/vkarpov15/kareem/commit/8bb3050))
+* fix: skip error handlers if no error ([0eb3a44](https://github.com/vkarpov15/kareem/commit/0eb3a44))
+
+
+
+<a name="1.1.0"></a>
+## 1.1.0 (2016-05-11)
+
+* chore: release 1.1.0 ([85332d9](https://github.com/vkarpov15/kareem/commit/85332d9))
+* chore: test on node 4 and node 5 ([1faefa1](https://github.com/vkarpov15/kareem/commit/1faefa1))
+* 100% coverage again ([c9aee4e](https://github.com/vkarpov15/kareem/commit/c9aee4e))
+* add support for error post hooks ([d378113](https://github.com/vkarpov15/kareem/commit/d378113))
+* basic setup for sync hooks #4 ([55aa081](https://github.com/vkarpov15/kareem/commit/55aa081)), closes [#4](https://github.com/vkarpov15/kareem/issues/4)
+* proof of concept for error handlers ([e4a07d9](https://github.com/vkarpov15/kareem/commit/e4a07d9))
+* refactor out handleWrapError helper ([b19af38](https://github.com/vkarpov15/kareem/commit/b19af38))
+
+
+
+<a name="1.0.1"></a>
+## <small>1.0.1 (2015-05-10)</small>
+
+* Fix #1 ([de60dc6](https://github.com/vkarpov15/kareem/commit/de60dc6)), closes [#1](https://github.com/vkarpov15/kareem/issues/1)
+* release 1.0.1 ([6971088](https://github.com/vkarpov15/kareem/commit/6971088))
+* Run tests on iojs in travis ([adcd201](https://github.com/vkarpov15/kareem/commit/adcd201))
+* support legacy post hook behavior in wrap() ([23fa74c](https://github.com/vkarpov15/kareem/commit/23fa74c))
+* Use node 0.12 in travis ([834689d](https://github.com/vkarpov15/kareem/commit/834689d))
+
+
+
+<a name="1.0.0"></a>
+## 1.0.0 (2015-01-28)
+
+* Tag 1.0.0 ([4c5a35a](https://github.com/vkarpov15/kareem/commit/4c5a35a))
+
+
+
+<a name="0.0.8"></a>
+## <small>0.0.8 (2015-01-27)</small>
+
+* Add clone function ([688bba7](https://github.com/vkarpov15/kareem/commit/688bba7))
+* Add jscs for style checking ([5c93149](https://github.com/vkarpov15/kareem/commit/5c93149))
+* Bump 0.0.8 ([03c0d2f](https://github.com/vkarpov15/kareem/commit/03c0d2f))
+* Fix jscs config, add gulp rules ([9989abf](https://github.com/vkarpov15/kareem/commit/9989abf))
+* fix Makefile typo ([1f7e61a](https://github.com/vkarpov15/kareem/commit/1f7e61a))
+
+
+
+<a name="0.0.7"></a>
+## <small>0.0.7 (2015-01-04)</small>
+
+* Bump 0.0.7 ([98ef173](https://github.com/vkarpov15/kareem/commit/98ef173))
+* fix LearnBoost/mongoose#2553 - use null instead of undefined for err ([9157b48](https://github.com/vkarpov15/kareem/commit/9157b48)), closes [LearnBoost/mongoose#2553](https://github.com/LearnBoost/mongoose/issues/2553)
+* Regenerate docs ([2331cdf](https://github.com/vkarpov15/kareem/commit/2331cdf))
+
+
+
+<a name="0.0.6"></a>
+## <small>0.0.6 (2015-01-01)</small>
+
+* Update docs and bump 0.0.6 ([92c12a7](https://github.com/vkarpov15/kareem/commit/92c12a7))
+
+
+
+<a name="0.0.5"></a>
+## <small>0.0.5 (2015-01-01)</small>
+
+* Add coverage rule to Makefile ([825a91c](https://github.com/vkarpov15/kareem/commit/825a91c))
+* Add coveralls to README ([fb52369](https://github.com/vkarpov15/kareem/commit/fb52369))
+* Add coveralls to travis ([93f6f15](https://github.com/vkarpov15/kareem/commit/93f6f15))
+* Add createWrapper() function ([ea77741](https://github.com/vkarpov15/kareem/commit/ea77741))
+* Add istanbul code coverage ([6eceeef](https://github.com/vkarpov15/kareem/commit/6eceeef))
+* Add some more comments for examples ([c5b0c6f](https://github.com/vkarpov15/kareem/commit/c5b0c6f))
+* Add travis ([e6dcb06](https://github.com/vkarpov15/kareem/commit/e6dcb06))
+* Add travis badge to docs ([ad8c9b3](https://github.com/vkarpov15/kareem/commit/ad8c9b3))
+* Add wrap() tests, 100% coverage ([6945be4](https://github.com/vkarpov15/kareem/commit/6945be4))
+* Better test coverage for execPost ([d9ad539](https://github.com/vkarpov15/kareem/commit/d9ad539))
+* Bump 0.0.5 ([69875b1](https://github.com/vkarpov15/kareem/commit/69875b1))
+* Docs fix ([15b7098](https://github.com/vkarpov15/kareem/commit/15b7098))
+* Fix silly mistake in docs generation ([50373eb](https://github.com/vkarpov15/kareem/commit/50373eb))
+* Fix typo in readme ([fec4925](https://github.com/vkarpov15/kareem/commit/fec4925))
+* Linkify travis badge ([92b25fe](https://github.com/vkarpov15/kareem/commit/92b25fe))
+* Make travis run coverage ([747157b](https://github.com/vkarpov15/kareem/commit/747157b))
+* Move travis status badge ([d52e89b](https://github.com/vkarpov15/kareem/commit/d52e89b))
+* Quick fix for coverage ([50bbddb](https://github.com/vkarpov15/kareem/commit/50bbddb))
+* Typo fix ([adea794](https://github.com/vkarpov15/kareem/commit/adea794))
+
+
+
+<a name="0.0.4"></a>
+## <small>0.0.4 (2014-12-13)</small>
+
+* Bump 0.0.4, run docs generation ([51a15fe](https://github.com/vkarpov15/kareem/commit/51a15fe))
+* Use correct post parameters in wrap() ([9bb5da3](https://github.com/vkarpov15/kareem/commit/9bb5da3))
+
+
+
+<a name="0.0.3"></a>
+## <small>0.0.3 (2014-12-12)</small>
+
+* Add npm test script, fix small bug with args not getting passed through post ([49e3e68](https://github.com/vkarpov15/kareem/commit/49e3e68))
+* Bump 0.0.3 ([65621d8](https://github.com/vkarpov15/kareem/commit/65621d8))
+* Update readme ([901388b](https://github.com/vkarpov15/kareem/commit/901388b))
+
+
+
+<a name="0.0.2"></a>
+## <small>0.0.2 (2014-12-12)</small>
+
+* Add github repo and bump 0.0.2 ([59db8be](https://github.com/vkarpov15/kareem/commit/59db8be))
+
+
+
+<a name="0.0.1"></a>
+## <small>0.0.1 (2014-12-12)</small>
+
+* Add basic docs ([ad29ea4](https://github.com/vkarpov15/kareem/commit/ad29ea4))
+* Add pre hooks ([2ffc356](https://github.com/vkarpov15/kareem/commit/2ffc356))
+* Add wrap function ([68c540c](https://github.com/vkarpov15/kareem/commit/68c540c))
+* Bump to version 0.0.1 ([a4bfd68](https://github.com/vkarpov15/kareem/commit/a4bfd68))
+* Initial commit ([4002458](https://github.com/vkarpov15/kareem/commit/4002458))
+* Initial deposit ([98fc489](https://github.com/vkarpov15/kareem/commit/98fc489))
+* Post hooks ([395b67c](https://github.com/vkarpov15/kareem/commit/395b67c))
+* Some basic setup work ([82df75e](https://github.com/vkarpov15/kareem/commit/82df75e))
+* Support sync pre hooks ([1cc1b9f](https://github.com/vkarpov15/kareem/commit/1cc1b9f))
+* Update package.json description ([978da18](https://github.com/vkarpov15/kareem/commit/978da18))
+
+
+
+<a name="2.2.5"></a>
+## <small>2.2.5 (2018-09-24)</small>
+
+
+
+
+<a name="2.2.4"></a>
+## <small>2.2.4 (2018-09-24)</small>
+
+
+
+
+<a name="2.2.3"></a>
+## <small>2.2.3 (2018-09-24)</small>
+
+* fix(filter): copy async pres correctly with `filter()` ([1b1ed8a](https://github.com/vkarpov15/kareem/commit/1b1ed8a)), closes [Automattic/mongoose#3054](https://github.com/Automattic/mongoose/issues/3054)
+* feat: add filter() function ([1f641f4](https://github.com/vkarpov15/kareem/commit/1f641f4))
+* feat: support storing options on pre and post hooks ([59220b9](https://github.com/vkarpov15/kareem/commit/59220b9))
+
+
+
+<a name="2.2.3"></a>
+## <small>2.2.3 (2018-09-10)</small>
+
+* chore: release 2.2.3 ([af653a3](https://github.com/vkarpov15/kareem/commit/af653a3))
+
+
+
+<a name="2.2.2"></a>
+## <small>2.2.2 (2018-09-10)</small>
+
+* chore: release 2.2.2 ([3f0144d](https://github.com/vkarpov15/kareem/commit/3f0144d))
+* fix: allow merge() to not clone ([e628d65](https://github.com/vkarpov15/kareem/commit/e628d65))
+
+
+
+<a name="2.2.1"></a>
+## <small>2.2.1 (2018-06-05)</small>
+
+* chore: release 2.2.1 ([4625a64](https://github.com/vkarpov15/kareem/commit/4625a64))
+* chore: remove lockfile from git ([7f3e4e6](https://github.com/vkarpov15/kareem/commit/7f3e4e6))
+* fix: handle numAsync correctly when merging ([fef8e7e](https://github.com/vkarpov15/kareem/commit/fef8e7e))
+* test: repro issue with not copying numAsync ([952d9db](https://github.com/vkarpov15/kareem/commit/952d9db))
+
+
+
+<a name="2.2.0"></a>
+## 2.2.0 (2018-06-05)
+
+* chore: release 2.2.0 ([ff9ad03](https://github.com/vkarpov15/kareem/commit/ff9ad03))
+* fix: use maps instead of objects for _pres and _posts so `toString()` doesn't get reported as having ([55df303](https://github.com/vkarpov15/kareem/commit/55df303)), closes [Automattic/mongoose#6538](https://github.com/Automattic/mongoose/issues/6538)
+
+
+
+<a name="2.1.0"></a>
+## 2.1.0 (2018-05-16)
+
+* chore: release 2.1.0 ([ba5f1bc](https://github.com/vkarpov15/kareem/commit/ba5f1bc))
+* feat: add option to check wrapped function return value for promises ([c9d7dd1](https://github.com/vkarpov15/kareem/commit/c9d7dd1))
+* refactor: use const in wrap() ([0fc21f9](https://github.com/vkarpov15/kareem/commit/0fc21f9))
+
+
+
+<a name="2.0.7"></a>
+## <small>2.0.7 (2018-04-28)</small>
+
+* chore: release 2.0.7 ([0bf91e6](https://github.com/vkarpov15/kareem/commit/0bf91e6))
+* feat: add `hasHooks()` ([225f18d](https://github.com/vkarpov15/kareem/commit/225f18d)), closes [Automattic/mongoose#6385](https://github.com/Automattic/mongoose/issues/6385)
+
+
+
+<a name="2.0.6"></a>
+## <small>2.0.6 (2018-03-22)</small>
+
+* chore: release 2.0.6 ([f3d406b](https://github.com/vkarpov15/kareem/commit/f3d406b))
+* fix(wrap): ensure fast path still wraps function in `nextTick()` for chaining ([7000494](https://github.com/vkarpov15/kareem/commit/7000494)), closes [Automattic/mongoose#6250](https://github.com/Automattic/mongoose/issues/6250) [dsanel/mongoose-delete#36](https://github.com/dsanel/mongoose-delete/issues/36)
+
+
+
+<a name="2.0.5"></a>
+## <small>2.0.5 (2018-02-22)</small>
+
+* chore: release 2.0.5 ([3286612](https://github.com/vkarpov15/kareem/commit/3286612))
+* perf(createWrapper): don't create wrapper if there are no hooks ([5afc5b9](https://github.com/vkarpov15/kareem/commit/5afc5b9)), closes [Automattic/mongoose#6126](https://github.com/Automattic/mongoose/issues/6126)
+
+
+
+<a name="2.0.4"></a>
+## <small>2.0.4 (2018-02-08)</small>
+
+* chore: release 2.0.4 ([2ab0293](https://github.com/vkarpov15/kareem/commit/2ab0293))
+
+
+
+<a name="2.0.3"></a>
+## <small>2.0.3 (2018-02-01)</small>
+
+* chore: release 2.0.3 ([3c1abe5](https://github.com/vkarpov15/kareem/commit/3c1abe5))
+* fix: use process.nextTick() re: Automattic/mongoose#6074 ([e5bfe33](https://github.com/vkarpov15/kareem/commit/e5bfe33)), closes [Automattic/mongoose#6074](https://github.com/Automattic/mongoose/issues/6074)
+
+
+
+<a name="2.0.2"></a>
+## <small>2.0.2 (2018-01-24)</small>
+
+* chore: fix license ([a9d755c](https://github.com/vkarpov15/kareem/commit/a9d755c)), closes [#10](https://github.com/vkarpov15/kareem/issues/10)
+* chore: release 2.0.2 ([fe87ab6](https://github.com/vkarpov15/kareem/commit/fe87ab6))
+
+
+
+<a name="2.0.1"></a>
+## <small>2.0.1 (2018-01-09)</small>
+
+* chore: release 2.0.1 with lockfile bump ([09c44fb](https://github.com/vkarpov15/kareem/commit/09c44fb))
+
+
+
+<a name="2.0.0"></a>
+## 2.0.0 (2018-01-09)
+
+* chore: bump marked re: security ([cc564a9](https://github.com/vkarpov15/kareem/commit/cc564a9))
+* chore: release 2.0.0 ([f511d1c](https://github.com/vkarpov15/kareem/commit/f511d1c))
+
+
+
+<a name="2.0.0-rc5"></a>
+## 2.0.0-rc5 (2017-12-23)
+
+* chore: fix build on node 4+5 ([6dac5a4](https://github.com/vkarpov15/kareem/commit/6dac5a4))
+* chore: fix built on node 4 + 5 again ([434ef0a](https://github.com/vkarpov15/kareem/commit/434ef0a))
+* chore: release 2.0.0-rc5 ([25a32ee](https://github.com/vkarpov15/kareem/commit/25a32ee))
+
+
+
+<a name="2.0.0-rc4"></a>
+## 2.0.0-rc4 (2017-12-22)
+
+* chore: release 2.0.0-rc4 ([49fc083](https://github.com/vkarpov15/kareem/commit/49fc083))
+* BREAKING CHANGE: deduplicate when merging hooks re: Automattic/mongoose#2945 ([d458573](https://github.com/vkarpov15/kareem/commit/d458573)), closes [Automattic/mongoose#2945](https://github.com/Automattic/mongoose/issues/2945)
+
+
+
+<a name="2.0.0-rc3"></a>
+## 2.0.0-rc3 (2017-12-22)
+
+* chore: release 2.0.0-rc3 ([adaaa00](https://github.com/vkarpov15/kareem/commit/adaaa00))
+* feat: support returning promises from middleware functions ([05b4480](https://github.com/vkarpov15/kareem/commit/05b4480)), closes [Automattic/mongoose#3779](https://github.com/Automattic/mongoose/issues/3779)
+
+
+
+<a name="2.0.0-rc2"></a>
+## 2.0.0-rc2 (2017-12-21)
+
+* chore: release 2.0.0-rc2 ([76325fa](https://github.com/vkarpov15/kareem/commit/76325fa))
+* fix: ensure next() and done() run in next tick ([6c20684](https://github.com/vkarpov15/kareem/commit/6c20684))
+
+
+
+<a name="2.0.0-rc1"></a>
+## 2.0.0-rc1 (2017-12-21)
+
+* chore: improve test coverage re: Automattic/mongoose#3232 ([7b45cf0](https://github.com/vkarpov15/kareem/commit/7b45cf0)), closes [Automattic/mongoose#3232](https://github.com/Automattic/mongoose/issues/3232)
+* chore: release 2.0.0-rc1 ([9b83f52](https://github.com/vkarpov15/kareem/commit/9b83f52))
+* BREAKING CHANGE: report sync exceptions as errors, only allow calling next() and done() once ([674adcc](https://github.com/vkarpov15/kareem/commit/674adcc)), closes [Automattic/mongoose#3483](https://github.com/Automattic/mongoose/issues/3483)
+
+
+
+<a name="2.0.0-rc0"></a>
+## 2.0.0-rc0 (2017-12-17)
+
+* chore: release 2.0.0-rc0 ([16b44b5](https://github.com/vkarpov15/kareem/commit/16b44b5))
+* BREAKING CHANGE: drop support for node < 4 ([9cbb8c7](https://github.com/vkarpov15/kareem/commit/9cbb8c7))
+* BREAKING CHANGE: remove useLegacyPost and add several new features ([6dd8531](https://github.com/vkarpov15/kareem/commit/6dd8531)), closes [Automattic/mongoose#3232](https://github.com/Automattic/mongoose/issues/3232)
+
+
+
+<a name="1.5.0"></a>
+## 1.5.0 (2017-07-20)
+
+* chore: release 1.5.0 ([9c491a0](https://github.com/vkarpov15/kareem/commit/9c491a0))
+* fix: improve post error handlers results ([9928dd5](https://github.com/vkarpov15/kareem/commit/9928dd5)), closes [Automattic/mongoose#5466](https://github.com/Automattic/mongoose/issues/5466)
+
+
+
+<a name="1.4.2"></a>
+## <small>1.4.2 (2017-07-06)</small>
+
+* chore: release 1.4.2 ([8d14ac5](https://github.com/vkarpov15/kareem/commit/8d14ac5))
+* fix: correct args re: Automattic/mongoose#5405 ([3f28ae6](https://github.com/vkarpov15/kareem/commit/3f28ae6)), closes [Automattic/mongoose#5405](https://github.com/Automattic/mongoose/issues/5405)
+
+
+
+<a name="1.4.1"></a>
+## <small>1.4.1 (2017-04-25)</small>
+
+* chore: release 1.4.1 ([5ecf0c2](https://github.com/vkarpov15/kareem/commit/5ecf0c2))
+* fix: handle numAsyncPres with clone() ([c72e857](https://github.com/vkarpov15/kareem/commit/c72e857)), closes [#8](https://github.com/vkarpov15/kareem/issues/8)
+* test: repro #8 ([9b4d6b2](https://github.com/vkarpov15/kareem/commit/9b4d6b2)), closes [#8](https://github.com/vkarpov15/kareem/issues/8)
+
+
+
+<a name="1.4.0"></a>
+## 1.4.0 (2017-04-19)
+
+* chore: release 1.4.0 ([101c5f5](https://github.com/vkarpov15/kareem/commit/101c5f5))
+* feat: add merge() function ([285325e](https://github.com/vkarpov15/kareem/commit/285325e))
+
+
+
+<a name="1.3.0"></a>
+## 1.3.0 (2017-03-26)
+
+* chore: release 1.3.0 ([f3a9e50](https://github.com/vkarpov15/kareem/commit/f3a9e50))
+* feat: pass function args to execPre ([4dd466d](https://github.com/vkarpov15/kareem/commit/4dd466d))
+
+
+
+<a name="1.2.1"></a>
+## <small>1.2.1 (2017-02-03)</small>
+
+* chore: release 1.2.1 ([d97081f](https://github.com/vkarpov15/kareem/commit/d97081f))
+* fix: filter out _kareemIgnored args for error handlers re: Automattic/mongoose#4925 ([ddc7aeb](https://github.com/vkarpov15/kareem/commit/ddc7aeb)), closes [Automattic/mongoose#4925](https://github.com/Automattic/mongoose/issues/4925)
+* fix: make error handlers handle errors in pre hooks ([af38033](https://github.com/vkarpov15/kareem/commit/af38033)), closes [Automattic/mongoose#4927](https://github.com/Automattic/mongoose/issues/4927)
+
+
+
+<a name="1.2.0"></a>
+## 1.2.0 (2017-01-02)
+
+* chore: release 1.2.0 ([033225c](https://github.com/vkarpov15/kareem/commit/033225c))
+* chore: upgrade deps ([f9e9a09](https://github.com/vkarpov15/kareem/commit/f9e9a09))
+* feat: add _kareemIgnore re: Automattic/mongoose#4836 ([7957771](https://github.com/vkarpov15/kareem/commit/7957771)), closes [Automattic/mongoose#4836](https://github.com/Automattic/mongoose/issues/4836)
+
+
+
+<a name="1.1.5"></a>
+## <small>1.1.5 (2016-12-13)</small>
+
+* chore: release 1.1.5 ([1a9f684](https://github.com/vkarpov15/kareem/commit/1a9f684))
+* fix: correct field name ([04a0e9d](https://github.com/vkarpov15/kareem/commit/04a0e9d))
+
+
+
+<a name="1.1.4"></a>
+## <small>1.1.4 (2016-12-09)</small>
+
+* chore: release 1.1.4 ([ece401c](https://github.com/vkarpov15/kareem/commit/ece401c))
+* chore: run tests on node 6 ([e0cb1cb](https://github.com/vkarpov15/kareem/commit/e0cb1cb))
+* fix: only copy own properties in clone() ([dfe28ce](https://github.com/vkarpov15/kareem/commit/dfe28ce)), closes [#7](https://github.com/vkarpov15/kareem/issues/7)
+
+
+
+<a name="1.1.3"></a>
+## <small>1.1.3 (2016-06-27)</small>
+
+* chore: release 1.1.3 ([87171c8](https://github.com/vkarpov15/kareem/commit/87171c8))
+* fix: couple more issues with arg processing ([c65f523](https://github.com/vkarpov15/kareem/commit/c65f523))
+
+
+
+<a name="1.1.2"></a>
+## <small>1.1.2 (2016-06-27)</small>
+
+* chore: release 1.1.2 ([8e102b6](https://github.com/vkarpov15/kareem/commit/8e102b6))
+* fix: add early return ([4feda4e](https://github.com/vkarpov15/kareem/commit/4feda4e))
+
+
+
+<a name="1.1.1"></a>
+## <small>1.1.1 (2016-06-27)</small>
+
+* chore: release 1.1.1 ([8bb3050](https://github.com/vkarpov15/kareem/commit/8bb3050))
+* fix: skip error handlers if no error ([0eb3a44](https://github.com/vkarpov15/kareem/commit/0eb3a44))
+
+
+
+<a name="1.1.0"></a>
+## 1.1.0 (2016-05-11)
+
+* chore: release 1.1.0 ([85332d9](https://github.com/vkarpov15/kareem/commit/85332d9))
+* chore: test on node 4 and node 5 ([1faefa1](https://github.com/vkarpov15/kareem/commit/1faefa1))
+* 100% coverage again ([c9aee4e](https://github.com/vkarpov15/kareem/commit/c9aee4e))
+* add support for error post hooks ([d378113](https://github.com/vkarpov15/kareem/commit/d378113))
+* basic setup for sync hooks #4 ([55aa081](https://github.com/vkarpov15/kareem/commit/55aa081)), closes [#4](https://github.com/vkarpov15/kareem/issues/4)
+* proof of concept for error handlers ([e4a07d9](https://github.com/vkarpov15/kareem/commit/e4a07d9))
+* refactor out handleWrapError helper ([b19af38](https://github.com/vkarpov15/kareem/commit/b19af38))
+
+
+
+<a name="1.0.1"></a>
+## <small>1.0.1 (2015-05-10)</small>
+
+* Fix #1 ([de60dc6](https://github.com/vkarpov15/kareem/commit/de60dc6)), closes [#1](https://github.com/vkarpov15/kareem/issues/1)
+* release 1.0.1 ([6971088](https://github.com/vkarpov15/kareem/commit/6971088))
+* Run tests on iojs in travis ([adcd201](https://github.com/vkarpov15/kareem/commit/adcd201))
+* support legacy post hook behavior in wrap() ([23fa74c](https://github.com/vkarpov15/kareem/commit/23fa74c))
+* Use node 0.12 in travis ([834689d](https://github.com/vkarpov15/kareem/commit/834689d))
+
+
+
+<a name="1.0.0"></a>
+## 1.0.0 (2015-01-28)
+
+* Tag 1.0.0 ([4c5a35a](https://github.com/vkarpov15/kareem/commit/4c5a35a))
+
+
+
+<a name="0.0.8"></a>
+## <small>0.0.8 (2015-01-27)</small>
+
+* Add clone function ([688bba7](https://github.com/vkarpov15/kareem/commit/688bba7))
+* Add jscs for style checking ([5c93149](https://github.com/vkarpov15/kareem/commit/5c93149))
+* Bump 0.0.8 ([03c0d2f](https://github.com/vkarpov15/kareem/commit/03c0d2f))
+* Fix jscs config, add gulp rules ([9989abf](https://github.com/vkarpov15/kareem/commit/9989abf))
+* fix Makefile typo ([1f7e61a](https://github.com/vkarpov15/kareem/commit/1f7e61a))
+
+
+
+<a name="0.0.7"></a>
+## <small>0.0.7 (2015-01-04)</small>
+
+* Bump 0.0.7 ([98ef173](https://github.com/vkarpov15/kareem/commit/98ef173))
+* fix LearnBoost/mongoose#2553 - use null instead of undefined for err ([9157b48](https://github.com/vkarpov15/kareem/commit/9157b48)), closes [LearnBoost/mongoose#2553](https://github.com/LearnBoost/mongoose/issues/2553)
+* Regenerate docs ([2331cdf](https://github.com/vkarpov15/kareem/commit/2331cdf))
+
+
+
+<a name="0.0.6"></a>
+## <small>0.0.6 (2015-01-01)</small>
+
+* Update docs and bump 0.0.6 ([92c12a7](https://github.com/vkarpov15/kareem/commit/92c12a7))
+
+
+
+<a name="0.0.5"></a>
+## <small>0.0.5 (2015-01-01)</small>
+
+* Add coverage rule to Makefile ([825a91c](https://github.com/vkarpov15/kareem/commit/825a91c))
+* Add coveralls to README ([fb52369](https://github.com/vkarpov15/kareem/commit/fb52369))
+* Add coveralls to travis ([93f6f15](https://github.com/vkarpov15/kareem/commit/93f6f15))
+* Add createWrapper() function ([ea77741](https://github.com/vkarpov15/kareem/commit/ea77741))
+* Add istanbul code coverage ([6eceeef](https://github.com/vkarpov15/kareem/commit/6eceeef))
+* Add some more comments for examples ([c5b0c6f](https://github.com/vkarpov15/kareem/commit/c5b0c6f))
+* Add travis ([e6dcb06](https://github.com/vkarpov15/kareem/commit/e6dcb06))
+* Add travis badge to docs ([ad8c9b3](https://github.com/vkarpov15/kareem/commit/ad8c9b3))
+* Add wrap() tests, 100% coverage ([6945be4](https://github.com/vkarpov15/kareem/commit/6945be4))
+* Better test coverage for execPost ([d9ad539](https://github.com/vkarpov15/kareem/commit/d9ad539))
+* Bump 0.0.5 ([69875b1](https://github.com/vkarpov15/kareem/commit/69875b1))
+* Docs fix ([15b7098](https://github.com/vkarpov15/kareem/commit/15b7098))
+* Fix silly mistake in docs generation ([50373eb](https://github.com/vkarpov15/kareem/commit/50373eb))
+* Fix typo in readme ([fec4925](https://github.com/vkarpov15/kareem/commit/fec4925))
+* Linkify travis badge ([92b25fe](https://github.com/vkarpov15/kareem/commit/92b25fe))
+* Make travis run coverage ([747157b](https://github.com/vkarpov15/kareem/commit/747157b))
+* Move travis status badge ([d52e89b](https://github.com/vkarpov15/kareem/commit/d52e89b))
+* Quick fix for coverage ([50bbddb](https://github.com/vkarpov15/kareem/commit/50bbddb))
+* Typo fix ([adea794](https://github.com/vkarpov15/kareem/commit/adea794))
+
+
+
+<a name="0.0.4"></a>
+## <small>0.0.4 (2014-12-13)</small>
+
+* Bump 0.0.4, run docs generation ([51a15fe](https://github.com/vkarpov15/kareem/commit/51a15fe))
+* Use correct post parameters in wrap() ([9bb5da3](https://github.com/vkarpov15/kareem/commit/9bb5da3))
+
+
+
+<a name="0.0.3"></a>
+## <small>0.0.3 (2014-12-12)</small>
+
+* Add npm test script, fix small bug with args not getting passed through post ([49e3e68](https://github.com/vkarpov15/kareem/commit/49e3e68))
+* Bump 0.0.3 ([65621d8](https://github.com/vkarpov15/kareem/commit/65621d8))
+* Update readme ([901388b](https://github.com/vkarpov15/kareem/commit/901388b))
+
+
+
+<a name="0.0.2"></a>
+## <small>0.0.2 (2014-12-12)</small>
+
+* Add github repo and bump 0.0.2 ([59db8be](https://github.com/vkarpov15/kareem/commit/59db8be))
+
+
+
+<a name="0.0.1"></a>
+## <small>0.0.1 (2014-12-12)</small>
+
+* Add basic docs ([ad29ea4](https://github.com/vkarpov15/kareem/commit/ad29ea4))
+* Add pre hooks ([2ffc356](https://github.com/vkarpov15/kareem/commit/2ffc356))
+* Add wrap function ([68c540c](https://github.com/vkarpov15/kareem/commit/68c540c))
+* Bump to version 0.0.1 ([a4bfd68](https://github.com/vkarpov15/kareem/commit/a4bfd68))
+* Initial commit ([4002458](https://github.com/vkarpov15/kareem/commit/4002458))
+* Initial deposit ([98fc489](https://github.com/vkarpov15/kareem/commit/98fc489))
+* Post hooks ([395b67c](https://github.com/vkarpov15/kareem/commit/395b67c))
+* Some basic setup work ([82df75e](https://github.com/vkarpov15/kareem/commit/82df75e))
+* Support sync pre hooks ([1cc1b9f](https://github.com/vkarpov15/kareem/commit/1cc1b9f))
+* Update package.json description ([978da18](https://github.com/vkarpov15/kareem/commit/978da18))
diff --git a/node_modules/kareem/LICENSE b/node_modules/kareem/LICENSE
new file mode 100644
index 0000000..e06d208
--- /dev/null
+++ b/node_modules/kareem/LICENSE
@@ -0,0 +1,202 @@
+Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
diff --git a/node_modules/kareem/Makefile b/node_modules/kareem/Makefile
new file mode 100644
index 0000000..f71ba90
--- /dev/null
+++ b/node_modules/kareem/Makefile
@@ -0,0 +1,5 @@
+docs:
+ node ./docs.js
+
+coverage:
+ ./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- -R spec ./test/*
diff --git a/node_modules/kareem/README.md b/node_modules/kareem/README.md
new file mode 100644
index 0000000..49a4abc
--- /dev/null
+++ b/node_modules/kareem/README.md
@@ -0,0 +1,428 @@
+# kareem
+
+ [![Build Status](https://travis-ci.org/vkarpov15/kareem.svg?branch=master)](https://travis-ci.org/vkarpov15/kareem)
+ [![Coverage Status](https://img.shields.io/coveralls/vkarpov15/kareem.svg)](https://coveralls.io/r/vkarpov15/kareem)
+
+Re-imagined take on the [hooks](http://npmjs.org/package/hooks) module, meant to offer additional flexibility in allowing you to execute hooks whenever necessary, as opposed to simply wrapping a single function.
+
+Named for the NBA's all-time leading scorer Kareem Abdul-Jabbar, known for his mastery of the [hook shot](http://en.wikipedia.org/wiki/Kareem_Abdul-Jabbar#Skyhook)
+
+<img src="http://upload.wikimedia.org/wikipedia/commons/0/00/Kareem-Abdul-Jabbar_Lipofsky.jpg" width="220">
+
+# API
+
+## pre hooks
+
+Much like [hooks](https://npmjs.org/package/hooks), kareem lets you define
+pre and post hooks: pre hooks are called before a given function executes.
+Unlike hooks, kareem stores hooks and other internal state in a separate
+object, rather than relying on inheritance. Furthermore, kareem exposes
+an `execPre()` function that allows you to execute your pre hooks when
+appropriate, giving you more fine-grained control over your function hooks.
+
+
+#### It runs without any hooks specified
+
+```javascript
+
+ hooks.execPre('cook', null, function() {
+ done();
+ });
+
+```
+
+#### It runs basic serial pre hooks
+
+pre hook functions take one parameter, a "done" function that you execute
+when your pre hook is finished.
+
+
+```javascript
+
+ var count = 0;
+
+ hooks.pre('cook', function(done) {
+ ++count;
+ done();
+ });
+
+ hooks.execPre('cook', null, function() {
+ assert.equal(1, count);
+ done();
+ });
+
+```
+
+#### It can run multipe pre hooks
+
+```javascript
+
+ var count1 = 0;
+ var count2 = 0;
+
+ hooks.pre('cook', function(done) {
+ ++count1;
+ done();
+ });
+
+ hooks.pre('cook', function(done) {
+ ++count2;
+ done();
+ });
+
+ hooks.execPre('cook', null, function() {
+ assert.equal(1, count1);
+ assert.equal(1, count2);
+ done();
+ });
+
+```
+
+#### It can run fully synchronous pre hooks
+
+If your pre hook function takes no parameters, its assumed to be
+fully synchronous.
+
+
+```javascript
+
+ var count1 = 0;
+ var count2 = 0;
+
+ hooks.pre('cook', function() {
+ ++count1;
+ });
+
+ hooks.pre('cook', function() {
+ ++count2;
+ });
+
+ hooks.execPre('cook', null, function(error) {
+ assert.equal(null, error);
+ assert.equal(1, count1);
+ assert.equal(1, count2);
+ done();
+ });
+
+```
+
+#### It properly attaches context to pre hooks
+
+Pre save hook functions are bound to the second parameter to `execPre()`
+
+
+```javascript
+
+ hooks.pre('cook', function(done) {
+ this.bacon = 3;
+ done();
+ });
+
+ hooks.pre('cook', function(done) {
+ this.eggs = 4;
+ done();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ // In the pre hooks, `this` will refer to `obj`
+ hooks.execPre('cook', obj, function(error) {
+ assert.equal(null, error);
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ done();
+ });
+
+```
+
+#### It can execute parallel (async) pre hooks
+
+Like the hooks module, you can declare "async" pre hooks - these take two
+parameters, the functions `next()` and `done()`. `next()` passes control to
+the next pre hook, but the underlying function won't be called until all
+async pre hooks have called `done()`.
+
+
+```javascript
+
+ hooks.pre('cook', true, function(next, done) {
+ this.bacon = 3;
+ next();
+ setTimeout(function() {
+ done();
+ }, 5);
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ next();
+ var _this = this;
+ setTimeout(function() {
+ _this.eggs = 4;
+ done();
+ }, 10);
+ });
+
+ hooks.pre('cook', function(next) {
+ this.waffles = false;
+ next();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ hooks.execPre('cook', obj, function() {
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ done();
+ });
+
+```
+
+#### It supports returning a promise
+
+You can also return a promise from your pre hooks instead of calling
+`next()`. When the returned promise resolves, kareem will kick off the
+next middleware.
+
+
+```javascript
+
+ hooks.pre('cook', function() {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ this.bacon = 3;
+ resolve();
+ }, 100);
+ });
+ });
+
+ var obj = { bacon: 0 };
+
+ hooks.execPre('cook', obj, function() {
+ assert.equal(3, obj.bacon);
+ done();
+ });
+
+```
+
+## post hooks
+
+#### It runs without any hooks specified
+
+```javascript
+
+ hooks.execPost('cook', null, [1], function(error, eggs) {
+ assert.ifError(error);
+ assert.equal(1, eggs);
+ done();
+ });
+
+```
+
+#### It executes with parameters passed in
+
+```javascript
+
+ hooks.post('cook', function(eggs, bacon, callback) {
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ callback();
+ });
+
+ hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
+ assert.ifError(error);
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ done();
+ });
+
+```
+
+#### It can use synchronous post hooks
+
+```javascript
+
+ var execed = {};
+
+ hooks.post('cook', function(eggs, bacon) {
+ execed.first = true;
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ });
+
+ hooks.post('cook', function(eggs, bacon, callback) {
+ execed.second = true;
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ callback();
+ });
+
+ hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
+ assert.ifError(error);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ done();
+ });
+
+```
+
+## wrap()
+
+#### It wraps pre and post calls into one call
+
+```javascript
+
+ hooks.pre('cook', true, function(next, done) {
+ this.bacon = 3;
+ next();
+ setTimeout(function() {
+ done();
+ }, 5);
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ next();
+ var _this = this;
+ setTimeout(function() {
+ _this.eggs = 4;
+ done();
+ }, 10);
+ });
+
+ hooks.pre('cook', function(next) {
+ this.waffles = false;
+ next();
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [obj];
+ args.push(function(error, result) {
+ assert.ifError(error);
+ assert.equal(null, error);
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal('no', obj.tofu);
+
+ assert.equal(obj, result);
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(o, callback) {
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal(undefined, obj.tofu);
+ callback(null, o);
+ },
+ obj,
+ args);
+
+```
+
+## createWrapper()
+
+#### It wraps wrap() into a callable function
+
+```javascript
+
+ hooks.pre('cook', true, function(next, done) {
+ this.bacon = 3;
+ next();
+ setTimeout(function() {
+ done();
+ }, 5);
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ next();
+ var _this = this;
+ setTimeout(function() {
+ _this.eggs = 4;
+ done();
+ }, 10);
+ });
+
+ hooks.pre('cook', function(next) {
+ this.waffles = false;
+ next();
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var cook = hooks.createWrapper(
+ 'cook',
+ function(o, callback) {
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal(undefined, obj.tofu);
+ callback(null, o);
+ },
+ obj);
+
+ cook(obj, function(error, result) {
+ assert.ifError(error);
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal('no', obj.tofu);
+
+ assert.equal(obj, result);
+ done();
+ });
+
+```
+
+## clone()
+
+#### It clones a Kareem object
+
+```javascript
+
+ var k1 = new Kareem();
+ k1.pre('cook', function() {});
+ k1.post('cook', function() {});
+
+ var k2 = k1.clone();
+ assert.deepEqual(['cook'], Object.keys(k2._pres));
+ assert.deepEqual(['cook'], Object.keys(k2._posts));
+
+```
+
+## merge()
+
+#### It pulls hooks from another Kareem object
+
+```javascript
+
+ var k1 = new Kareem();
+ var test1 = function() {};
+ k1.pre('cook', test1);
+ k1.post('cook', function() {});
+
+ var k2 = new Kareem();
+ var test2 = function() {};
+ k2.pre('cook', test2);
+ var k3 = k2.merge(k1);
+ assert.equal(k3._pres['cook'].length, 2);
+ assert.equal(k3._pres['cook'][0].fn, test2);
+ assert.equal(k3._pres['cook'][1].fn, test1);
+ assert.equal(k3._posts['cook'].length, 1);
+
+```
+
diff --git a/node_modules/kareem/docs.js b/node_modules/kareem/docs.js
new file mode 100644
index 0000000..4a8d4c8
--- /dev/null
+++ b/node_modules/kareem/docs.js
@@ -0,0 +1,37 @@
+var acquit = require('acquit');
+
+var content = require('fs').readFileSync('./test/examples.test.js').toString();
+var blocks = acquit.parse(content);
+
+var mdOutput =
+ '# kareem\n\n' +
+ ' [![Build Status](https://travis-ci.org/vkarpov15/kareem.svg?branch=master)](https://travis-ci.org/vkarpov15/kareem)\n' +
+ ' [![Coverage Status](https://img.shields.io/coveralls/vkarpov15/kareem.svg)](https://coveralls.io/r/vkarpov15/kareem)\n\n' +
+ 'Re-imagined take on the [hooks](http://npmjs.org/package/hooks) module, ' +
+ 'meant to offer additional flexibility in allowing you to execute hooks ' +
+ 'whenever necessary, as opposed to simply wrapping a single function.\n\n' +
+ 'Named for the NBA\'s all-time leading scorer Kareem Abdul-Jabbar, known ' +
+ 'for his mastery of the [hook shot](http://en.wikipedia.org/wiki/Kareem_Abdul-Jabbar#Skyhook)\n\n' +
+ '<img src="http://upload.wikimedia.org/wikipedia/commons/0/00/Kareem-Abdul-Jabbar_Lipofsky.jpg" width="220">\n\n' +
+ '# API\n\n';
+
+for (var i = 0; i < blocks.length; ++i) {
+ var describe = blocks[i];
+ mdOutput += '## ' + describe.contents + '\n\n';
+ mdOutput += describe.comments[0] ?
+ acquit.trimEachLine(describe.comments[0]) + '\n\n' :
+ '';
+
+ for (var j = 0; j < describe.blocks.length; ++j) {
+ var it = describe.blocks[j];
+ mdOutput += '#### It ' + it.contents + '\n\n';
+ mdOutput += it.comments[0] ?
+ acquit.trimEachLine(it.comments[0]) + '\n\n' :
+ '';
+ mdOutput += '```javascript\n';
+ mdOutput += ' ' + it.code + '\n';
+ mdOutput += '```\n\n';
+ }
+}
+
+require('fs').writeFileSync('README.md', mdOutput);
diff --git a/node_modules/kareem/gulpfile.js b/node_modules/kareem/gulpfile.js
new file mode 100644
index 0000000..635bfc7
--- /dev/null
+++ b/node_modules/kareem/gulpfile.js
@@ -0,0 +1,18 @@
+var gulp = require('gulp');
+var mocha = require('gulp-mocha');
+var config = require('./package.json');
+var jscs = require('gulp-jscs');
+
+gulp.task('mocha', function() {
+ return gulp.src('./test/*').
+ pipe(mocha({ reporter: 'dot' }));
+});
+
+gulp.task('jscs', function() {
+ return gulp.src('./index.js').
+ pipe(jscs(config.jscsConfig));
+});
+
+gulp.task('watch', function() {
+ gulp.watch('./index.js', ['jscs', 'mocha']);
+});
diff --git a/node_modules/kareem/index.js b/node_modules/kareem/index.js
new file mode 100644
index 0000000..31ccb41
--- /dev/null
+++ b/node_modules/kareem/index.js
@@ -0,0 +1,511 @@
+'use strict';
+
+function Kareem() {
+ this._pres = new Map();
+ this._posts = new Map();
+}
+
+Kareem.prototype.execPre = function(name, context, args, callback) {
+ if (arguments.length === 3) {
+ callback = args;
+ args = [];
+ }
+ var pres = get(this._pres, name, []);
+ var numPres = pres.length;
+ var numAsyncPres = pres.numAsync || 0;
+ var currentPre = 0;
+ var asyncPresLeft = numAsyncPres;
+ var done = false;
+ var $args = args;
+
+ if (!numPres) {
+ return process.nextTick(function() {
+ callback(null);
+ });
+ }
+
+ var next = function() {
+ if (currentPre >= numPres) {
+ return;
+ }
+ var pre = pres[currentPre];
+
+ if (pre.isAsync) {
+ var args = [
+ decorateNextFn(_next),
+ decorateNextFn(function(error) {
+ if (error) {
+ if (done) {
+ return;
+ }
+ done = true;
+ return callback(error);
+ }
+ if (--asyncPresLeft === 0 && currentPre >= numPres) {
+ return callback(null);
+ }
+ })
+ ];
+
+ callMiddlewareFunction(pre.fn, context, args, args[0]);
+ } else if (pre.fn.length > 0) {
+ var args = [decorateNextFn(_next)];
+ var _args = arguments.length >= 2 ? arguments : [null].concat($args);
+ for (var i = 1; i < _args.length; ++i) {
+ args.push(_args[i]);
+ }
+
+ callMiddlewareFunction(pre.fn, context, args, args[0]);
+ } else {
+ let error = null;
+ let maybePromise = null;
+ try {
+ maybePromise = pre.fn.call(context);
+ } catch (err) {
+ error = err;
+ }
+
+ if (isPromise(maybePromise)) {
+ maybePromise.then(() => _next(), err => _next(err));
+ } else {
+ if (++currentPre >= numPres) {
+ if (asyncPresLeft > 0) {
+ // Leave parallel hooks to run
+ return;
+ } else {
+ return process.nextTick(function() {
+ callback(error);
+ });
+ }
+ }
+ next(error);
+ }
+ }
+ };
+
+ next.apply(null, [null].concat(args));
+
+ function _next(error) {
+ if (error) {
+ if (done) {
+ return;
+ }
+ done = true;
+ return callback(error);
+ }
+
+ if (++currentPre >= numPres) {
+ if (asyncPresLeft > 0) {
+ // Leave parallel hooks to run
+ return;
+ } else {
+ return callback(null);
+ }
+ }
+
+ next.apply(context, arguments);
+ }
+};
+
+Kareem.prototype.execPreSync = function(name, context, args) {
+ var pres = get(this._pres, name, []);
+ var numPres = pres.length;
+
+ for (var i = 0; i < numPres; ++i) {
+ pres[i].fn.apply(context, args || []);
+ }
+};
+
+Kareem.prototype.execPost = function(name, context, args, options, callback) {
+ if (arguments.length < 5) {
+ callback = options;
+ options = null;
+ }
+ var posts = get(this._posts, name, []);
+ var numPosts = posts.length;
+ var currentPost = 0;
+
+ var firstError = null;
+ if (options && options.error) {
+ firstError = options.error;
+ }
+
+ if (!numPosts) {
+ return process.nextTick(function() {
+ callback.apply(null, [firstError].concat(args));
+ });
+ }
+
+ var next = function() {
+ var post = posts[currentPost].fn;
+ var numArgs = 0;
+ var argLength = args.length;
+ var newArgs = [];
+ for (var i = 0; i < argLength; ++i) {
+ numArgs += args[i] && args[i]._kareemIgnore ? 0 : 1;
+ if (!args[i] || !args[i]._kareemIgnore) {
+ newArgs.push(args[i]);
+ }
+ }
+
+ if (firstError) {
+ if (post.length === numArgs + 2) {
+ var _cb = decorateNextFn(function(error) {
+ if (error) {
+ firstError = error;
+ }
+ if (++currentPost >= numPosts) {
+ return callback.call(null, firstError);
+ }
+ next();
+ });
+
+ callMiddlewareFunction(post, context,
+ [firstError].concat(newArgs).concat([_cb]), _cb);
+ } else {
+ if (++currentPost >= numPosts) {
+ return callback.call(null, firstError);
+ }
+ next();
+ }
+ } else {
+ const _cb = decorateNextFn(function(error) {
+ if (error) {
+ firstError = error;
+ return next();
+ }
+
+ if (++currentPost >= numPosts) {
+ return callback.apply(null, [null].concat(args));
+ }
+
+ next();
+ });
+
+ if (post.length === numArgs + 2) {
+ // Skip error handlers if no error
+ if (++currentPost >= numPosts) {
+ return callback.apply(null, [null].concat(args));
+ }
+ return next();
+ }
+ if (post.length === numArgs + 1) {
+ callMiddlewareFunction(post, context, newArgs.concat([_cb]), _cb);
+ } else {
+ let error;
+ let maybePromise;
+ try {
+ maybePromise = post.apply(context, newArgs);
+ } catch (err) {
+ error = err;
+ firstError = err;
+ }
+
+ if (isPromise(maybePromise)) {
+ return maybePromise.then(() => _cb(), err => _cb(err));
+ }
+
+ if (++currentPost >= numPosts) {
+ return callback.apply(null, [error].concat(args));
+ }
+
+ next(error);
+ }
+ }
+ };
+
+ next();
+};
+
+Kareem.prototype.execPostSync = function(name, context, args) {
+ const posts = get(this._posts, name, []);
+ const numPosts = posts.length;
+
+ for (let i = 0; i < numPosts; ++i) {
+ posts[i].fn.apply(context, args || []);
+ }
+};
+
+Kareem.prototype.createWrapperSync = function(name, fn) {
+ var kareem = this;
+ return function syncWrapper() {
+ kareem.execPreSync(name, this, arguments);
+
+ var toReturn = fn.apply(this, arguments);
+
+ kareem.execPostSync(name, this, [toReturn]);
+
+ return toReturn;
+ };
+}
+
+function _handleWrapError(instance, error, name, context, args, options, callback) {
+ if (options.useErrorHandlers) {
+ var _options = { error: error };
+ return instance.execPost(name, context, args, _options, function(error) {
+ return typeof callback === 'function' && callback(error);
+ });
+ } else {
+ return typeof callback === 'function' ?
+ callback(error) :
+ undefined;
+ }
+}
+
+Kareem.prototype.wrap = function(name, fn, context, args, options) {
+ const lastArg = (args.length > 0 ? args[args.length - 1] : null);
+ const argsWithoutCb = typeof lastArg === 'function' ?
+ args.slice(0, args.length - 1) :
+ args;
+ const _this = this;
+
+ options = options || {};
+ const checkForPromise = options.checkForPromise;
+
+ this.execPre(name, context, args, function(error) {
+ if (error) {
+ const numCallbackParams = options.numCallbackParams || 0;
+ const errorArgs = options.contextParameter ? [context] : [];
+ for (var i = errorArgs.length; i < numCallbackParams; ++i) {
+ errorArgs.push(null);
+ }
+ return _handleWrapError(_this, error, name, context, errorArgs,
+ options, lastArg);
+ }
+
+ const end = (typeof lastArg === 'function' ? args.length - 1 : args.length);
+ const numParameters = fn.length;
+ const ret = fn.apply(context, args.slice(0, end).concat(_cb));
+
+ if (checkForPromise) {
+ if (ret != null && typeof ret.then === 'function') {
+ // Thenable, use it
+ return ret.then(
+ res => _cb(null, res),
+ err => _cb(err)
+ );
+ }
+
+ // If `fn()` doesn't have a callback argument and doesn't return a
+ // promise, assume it is sync
+ if (numParameters < end + 1) {
+ return _cb(null, ret);
+ }
+ }
+
+ function _cb() {
+ const args = arguments;
+ const argsWithoutError = Array.prototype.slice.call(arguments, 1);
+ if (options.nullResultByDefault && argsWithoutError.length === 0) {
+ argsWithoutError.push(null);
+ }
+ if (arguments[0]) {
+ // Assume error
+ return _handleWrapError(_this, arguments[0], name, context,
+ argsWithoutError, options, lastArg);
+ } else {
+ _this.execPost(name, context, argsWithoutError, function() {
+ if (arguments[0]) {
+ return typeof lastArg === 'function' ?
+ lastArg(arguments[0]) :
+ undefined;
+ }
+
+ return typeof lastArg === 'function' ?
+ lastArg.apply(context, arguments) :
+ undefined;
+ });
+ }
+ }
+ });
+};
+
+Kareem.prototype.filter = function(fn) {
+ const clone = this.clone();
+
+ const pres = Array.from(clone._pres.keys());
+ for (const name of pres) {
+ const hooks = this._pres.get(name).
+ map(h => Object.assign({}, h, { name: name })).
+ filter(fn);
+
+ if (hooks.length === 0) {
+ clone._pres.delete(name);
+ continue;
+ }
+
+ hooks.numAsync = hooks.filter(h => h.isAsync).length;
+
+ clone._pres.set(name, hooks);
+ }
+
+ const posts = Array.from(clone._posts.keys());
+ for (const name of posts) {
+ const hooks = this._posts.get(name).
+ map(h => Object.assign({}, h, { name: name })).
+ filter(fn);
+
+ if (hooks.length === 0) {
+ clone._posts.delete(name);
+ continue;
+ }
+
+ clone._posts.set(name, hooks);
+ }
+
+ return clone;
+};
+
+Kareem.prototype.hasHooks = function(name) {
+ return this._pres.has(name) || this._posts.has(name);
+};
+
+Kareem.prototype.createWrapper = function(name, fn, context, options) {
+ var _this = this;
+ if (!this.hasHooks(name)) {
+ // Fast path: if there's no hooks for this function, just return the
+ // function wrapped in a nextTick()
+ return function() {
+ process.nextTick(() => fn.apply(this, arguments));
+ };
+ }
+ return function() {
+ var _context = context || this;
+ var args = Array.prototype.slice.call(arguments);
+ _this.wrap(name, fn, _context, args, options);
+ };
+};
+
+Kareem.prototype.pre = function(name, isAsync, fn, error, unshift) {
+ let options = {};
+ if (typeof isAsync === 'object' && isAsync != null) {
+ options = isAsync;
+ isAsync = options.isAsync;
+ } else if (typeof arguments[1] !== 'boolean') {
+ error = fn;
+ fn = isAsync;
+ isAsync = false;
+ }
+
+ const pres = get(this._pres, name, []);
+ this._pres.set(name, pres);
+
+ if (isAsync) {
+ pres.numAsync = pres.numAsync || 0;
+ ++pres.numAsync;
+ }
+
+ if (typeof fn !== 'function') {
+ throw new Error('pre() requires a function, got "' + typeof fn + '"');
+ }
+
+ if (unshift) {
+ pres.unshift(Object.assign({}, options, { fn: fn, isAsync: isAsync }));
+ } else {
+ pres.push(Object.assign({}, options, { fn: fn, isAsync: isAsync }));
+ }
+
+ return this;
+};
+
+Kareem.prototype.post = function(name, options, fn, unshift) {
+ const hooks = get(this._posts, name, []);
+
+ if (typeof options === 'function') {
+ unshift = !!fn;
+ fn = options;
+ options = {};
+ }
+
+ if (typeof fn !== 'function') {
+ throw new Error('post() requires a function, got "' + typeof fn + '"');
+ }
+
+ if (unshift) {
+ hooks.unshift(Object.assign({}, options, { fn: fn }));
+ } else {
+ hooks.push(Object.assign({}, options, { fn: fn }));
+ }
+ this._posts.set(name, hooks);
+ return this;
+};
+
+Kareem.prototype.clone = function() {
+ const n = new Kareem();
+
+ for (let key of this._pres.keys()) {
+ const clone = this._pres.get(key).slice();
+ clone.numAsync = this._pres.get(key).numAsync;
+ n._pres.set(key, clone);
+ }
+ for (let key of this._posts.keys()) {
+ n._posts.set(key, this._posts.get(key).slice());
+ }
+
+ return n;
+};
+
+Kareem.prototype.merge = function(other, clone) {
+ clone = arguments.length === 1 ? true : clone;
+ var ret = clone ? this.clone() : this;
+
+ for (let key of other._pres.keys()) {
+ const sourcePres = get(ret._pres, key, []);
+ const deduplicated = other._pres.get(key).
+ // Deduplicate based on `fn`
+ filter(p => sourcePres.map(_p => _p.fn).indexOf(p.fn) === -1);
+ const combined = sourcePres.concat(deduplicated);
+ combined.numAsync = sourcePres.numAsync || 0;
+ combined.numAsync += deduplicated.filter(p => p.isAsync).length;
+ ret._pres.set(key, combined);
+ }
+ for (let key of other._posts.keys()) {
+ const sourcePosts = get(ret._posts, key, []);
+ const deduplicated = other._posts.get(key).
+ filter(p => sourcePosts.indexOf(p) === -1);
+ ret._posts.set(key, sourcePosts.concat(deduplicated));
+ }
+
+ return ret;
+};
+
+function get(map, key, def) {
+ if (map.has(key)) {
+ return map.get(key);
+ }
+ return def;
+}
+
+function callMiddlewareFunction(fn, context, args, next) {
+ let maybePromise;
+ try {
+ maybePromise = fn.apply(context, args);
+ } catch (error) {
+ return next(error);
+ }
+
+ if (isPromise(maybePromise)) {
+ maybePromise.then(() => next(), err => next(err));
+ }
+}
+
+function isPromise(v) {
+ return v != null && typeof v.then === 'function';
+}
+
+function decorateNextFn(fn) {
+ var called = false;
+ var _this = this;
+ return function() {
+ // Ensure this function can only be called once
+ if (called) {
+ return;
+ }
+ called = true;
+ // Make sure to clear the stack so try/catch doesn't catch errors
+ // in subsequent middleware
+ return process.nextTick(() => fn.apply(_this, arguments));
+ };
+}
+
+module.exports = Kareem;
diff --git a/node_modules/kareem/package.json b/node_modules/kareem/package.json
new file mode 100644
index 0000000..8909749
--- /dev/null
+++ b/node_modules/kareem/package.json
@@ -0,0 +1,53 @@
+{
+ "_from": "kareem@2.3.1",
+ "_id": "kareem@2.3.1",
+ "_inBundle": false,
+ "_integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==",
+ "_location": "/kareem",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "version",
+ "registry": true,
+ "raw": "kareem@2.3.1",
+ "name": "kareem",
+ "escapedName": "kareem",
+ "rawSpec": "2.3.1",
+ "saveSpec": null,
+ "fetchSpec": "2.3.1"
+ },
+ "_requiredBy": [
+ "/mongoose"
+ ],
+ "_resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
+ "_shasum": "def12d9c941017fabfb00f873af95e9c99e1be87",
+ "_spec": "kareem@2.3.1",
+ "_where": "/home/pruss/Dev/3-minute-website/node_modules/mongoose",
+ "author": {
+ "name": "Valeri Karpov",
+ "email": "val@karpov.io"
+ },
+ "bugs": {
+ "url": "https://github.com/vkarpov15/kareem/issues"
+ },
+ "bundleDependencies": false,
+ "deprecated": false,
+ "description": "Next-generation take on pre/post function hooks",
+ "devDependencies": {
+ "mocha": "5.x",
+ "nyc": "11.x",
+ "standard-version": "4.4.0"
+ },
+ "homepage": "https://github.com/vkarpov15/kareem#readme",
+ "license": "Apache-2.0",
+ "main": "index.js",
+ "name": "kareem",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/vkarpov15/kareem.git"
+ },
+ "scripts": {
+ "test": "mocha ./test/*",
+ "test-travis": "nyc mocha ./test/*"
+ },
+ "version": "2.3.1"
+}
diff --git a/node_modules/kareem/test/examples.test.js b/node_modules/kareem/test/examples.test.js
new file mode 100644
index 0000000..f120723
--- /dev/null
+++ b/node_modules/kareem/test/examples.test.js
@@ -0,0 +1,379 @@
+var assert = require('assert');
+var Kareem = require('../');
+
+/* Much like [hooks](https://npmjs.org/package/hooks), kareem lets you define
+ * pre and post hooks: pre hooks are called before a given function executes.
+ * Unlike hooks, kareem stores hooks and other internal state in a separate
+ * object, rather than relying on inheritance. Furthermore, kareem exposes
+ * an `execPre()` function that allows you to execute your pre hooks when
+ * appropriate, giving you more fine-grained control over your function hooks.
+ */
+describe('pre hooks', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('runs without any hooks specified', function(done) {
+ hooks.execPre('cook', null, function() {
+ done();
+ });
+ });
+
+ /* pre hook functions take one parameter, a "done" function that you execute
+ * when your pre hook is finished.
+ */
+ it('runs basic serial pre hooks', function(done) {
+ var count = 0;
+
+ hooks.pre('cook', function(done) {
+ ++count;
+ done();
+ });
+
+ hooks.execPre('cook', null, function() {
+ assert.equal(1, count);
+ done();
+ });
+ });
+
+ it('can run multipe pre hooks', function(done) {
+ var count1 = 0;
+ var count2 = 0;
+
+ hooks.pre('cook', function(done) {
+ ++count1;
+ done();
+ });
+
+ hooks.pre('cook', function(done) {
+ ++count2;
+ done();
+ });
+
+ hooks.execPre('cook', null, function() {
+ assert.equal(1, count1);
+ assert.equal(1, count2);
+ done();
+ });
+ });
+
+ /* If your pre hook function takes no parameters, its assumed to be
+ * fully synchronous.
+ */
+ it('can run fully synchronous pre hooks', function(done) {
+ var count1 = 0;
+ var count2 = 0;
+
+ hooks.pre('cook', function() {
+ ++count1;
+ });
+
+ hooks.pre('cook', function() {
+ ++count2;
+ });
+
+ hooks.execPre('cook', null, function(error) {
+ assert.equal(null, error);
+ assert.equal(1, count1);
+ assert.equal(1, count2);
+ done();
+ });
+ });
+
+ /* Pre save hook functions are bound to the second parameter to `execPre()`
+ */
+ it('properly attaches context to pre hooks', function(done) {
+ hooks.pre('cook', function(done) {
+ this.bacon = 3;
+ done();
+ });
+
+ hooks.pre('cook', function(done) {
+ this.eggs = 4;
+ done();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ // In the pre hooks, `this` will refer to `obj`
+ hooks.execPre('cook', obj, function(error) {
+ assert.equal(null, error);
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ done();
+ });
+ });
+
+ /* Like the hooks module, you can declare "async" pre hooks - these take two
+ * parameters, the functions `next()` and `done()`. `next()` passes control to
+ * the next pre hook, but the underlying function won't be called until all
+ * async pre hooks have called `done()`.
+ */
+ it('can execute parallel (async) pre hooks', function(done) {
+ hooks.pre('cook', true, function(next, done) {
+ this.bacon = 3;
+ next();
+ setTimeout(function() {
+ done();
+ }, 5);
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ next();
+ var _this = this;
+ setTimeout(function() {
+ _this.eggs = 4;
+ done();
+ }, 10);
+ });
+
+ hooks.pre('cook', function(next) {
+ this.waffles = false;
+ next();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ hooks.execPre('cook', obj, function() {
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ done();
+ });
+ });
+
+ /* You can also return a promise from your pre hooks instead of calling
+ * `next()`. When the returned promise resolves, kareem will kick off the
+ * next middleware.
+ */
+ it('supports returning a promise', function(done) {
+ hooks.pre('cook', function() {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ this.bacon = 3;
+ resolve();
+ }, 100);
+ });
+ });
+
+ var obj = { bacon: 0 };
+
+ hooks.execPre('cook', obj, function() {
+ assert.equal(3, obj.bacon);
+ done();
+ });
+ });
+});
+
+describe('post hooks', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('runs without any hooks specified', function(done) {
+ hooks.execPost('cook', null, [1], function(error, eggs) {
+ assert.ifError(error);
+ assert.equal(1, eggs);
+ done();
+ });
+ });
+
+ it('executes with parameters passed in', function(done) {
+ hooks.post('cook', function(eggs, bacon, callback) {
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ callback();
+ });
+
+ hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
+ assert.ifError(error);
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ done();
+ });
+ });
+
+ it('can use synchronous post hooks', function(done) {
+ var execed = {};
+
+ hooks.post('cook', function(eggs, bacon) {
+ execed.first = true;
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ });
+
+ hooks.post('cook', function(eggs, bacon, callback) {
+ execed.second = true;
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ callback();
+ });
+
+ hooks.execPost('cook', null, [1, 2], function(error, eggs, bacon) {
+ assert.ifError(error);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ assert.equal(1, eggs);
+ assert.equal(2, bacon);
+ done();
+ });
+ });
+});
+
+describe('wrap()', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('wraps pre and post calls into one call', function(done) {
+ hooks.pre('cook', true, function(next, done) {
+ this.bacon = 3;
+ next();
+ setTimeout(function() {
+ done();
+ }, 5);
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ next();
+ var _this = this;
+ setTimeout(function() {
+ _this.eggs = 4;
+ done();
+ }, 10);
+ });
+
+ hooks.pre('cook', function(next) {
+ this.waffles = false;
+ next();
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [obj];
+ args.push(function(error, result) {
+ assert.ifError(error);
+ assert.equal(null, error);
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal('no', obj.tofu);
+
+ assert.equal(obj, result);
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(o, callback) {
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal(undefined, obj.tofu);
+ callback(null, o);
+ },
+ obj,
+ args);
+ });
+});
+
+describe('createWrapper()', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('wraps wrap() into a callable function', function(done) {
+ hooks.pre('cook', true, function(next, done) {
+ this.bacon = 3;
+ next();
+ setTimeout(function() {
+ done();
+ }, 5);
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ next();
+ var _this = this;
+ setTimeout(function() {
+ _this.eggs = 4;
+ done();
+ }, 10);
+ });
+
+ hooks.pre('cook', function(next) {
+ this.waffles = false;
+ next();
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var cook = hooks.createWrapper(
+ 'cook',
+ function(o, callback) {
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal(undefined, obj.tofu);
+ callback(null, o);
+ },
+ obj);
+
+ cook(obj, function(error, result) {
+ assert.ifError(error);
+ assert.equal(3, obj.bacon);
+ assert.equal(4, obj.eggs);
+ assert.equal(false, obj.waffles);
+ assert.equal('no', obj.tofu);
+
+ assert.equal(obj, result);
+ done();
+ });
+ });
+});
+
+describe('clone()', function() {
+ it('clones a Kareem object', function() {
+ var k1 = new Kareem();
+ k1.pre('cook', function() {});
+ k1.post('cook', function() {});
+
+ var k2 = k1.clone();
+ assert.deepEqual(Array.from(k2._pres.keys()), ['cook']);
+ assert.deepEqual(Array.from(k2._posts.keys()), ['cook']);
+ });
+});
+
+describe('merge()', function() {
+ it('pulls hooks from another Kareem object', function() {
+ var k1 = new Kareem();
+ var test1 = function() {};
+ k1.pre('cook', test1);
+ k1.post('cook', function() {});
+
+ var k2 = new Kareem();
+ var test2 = function() {};
+ k2.pre('cook', test2);
+ var k3 = k2.merge(k1);
+ assert.equal(k3._pres.get('cook').length, 2);
+ assert.equal(k3._pres.get('cook')[0].fn, test2);
+ assert.equal(k3._pres.get('cook')[1].fn, test1);
+ assert.equal(k3._posts.get('cook').length, 1);
+ });
+});
diff --git a/node_modules/kareem/test/misc.test.js b/node_modules/kareem/test/misc.test.js
new file mode 100644
index 0000000..531b1d4
--- /dev/null
+++ b/node_modules/kareem/test/misc.test.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const assert = require('assert');
+const Kareem = require('../');
+
+describe('hasHooks', function() {
+ it('returns false for toString (Automattic/mongoose#6538)', function() {
+ const k = new Kareem();
+ assert.ok(!k.hasHooks('toString'));
+ });
+});
+
+describe('merge', function() {
+ it('handles async pres if source doesnt have them', function() {
+ const k1 = new Kareem();
+ k1.pre('cook', true, function(next, done) {
+ execed.first = true;
+ setTimeout(
+ function() {
+ done('error!');
+ },
+ 5);
+
+ next();
+ });
+
+ assert.equal(k1._pres.get('cook').numAsync, 1);
+
+ const k2 = new Kareem();
+ const k3 = k2.merge(k1);
+ assert.equal(k3._pres.get('cook').numAsync, 1);
+ });
+});
+
+describe('filter', function() {
+ it('returns clone with only hooks that match `fn()`', function() {
+ const k1 = new Kareem();
+
+ k1.pre('update', { document: true }, f1);
+ k1.pre('update', { query: true }, f2);
+ k1.pre('remove', { document: true }, f3);
+
+ k1.post('update', { document: true }, f1);
+ k1.post('update', { query: true }, f2);
+ k1.post('remove', { document: true }, f3);
+
+ const k2 = k1.filter(hook => hook.document);
+ assert.equal(k2._pres.get('update').length, 1);
+ assert.equal(k2._pres.get('update')[0].fn, f1);
+ assert.equal(k2._pres.get('remove').length, 1);
+ assert.equal(k2._pres.get('remove')[0].fn, f3);
+
+ assert.equal(k2._posts.get('update').length, 1);
+ assert.equal(k2._posts.get('update')[0].fn, f1);
+ assert.equal(k2._posts.get('remove').length, 1);
+ assert.equal(k2._posts.get('remove')[0].fn, f3);
+
+ const k3 = k1.filter(hook => hook.query);
+ assert.equal(k3._pres.get('update').length, 1);
+ assert.equal(k3._pres.get('update')[0].fn, f2);
+ assert.ok(!k3._pres.has('remove'));
+
+ assert.equal(k3._posts.get('update').length, 1);
+ assert.equal(k3._posts.get('update')[0].fn, f2);
+ assert.ok(!k3._posts.has('remove'));
+
+ function f1() {}
+ function f2() {}
+ function f3() {}
+ });
+});
diff --git a/node_modules/kareem/test/post.test.js b/node_modules/kareem/test/post.test.js
new file mode 100644
index 0000000..b9a776d
--- /dev/null
+++ b/node_modules/kareem/test/post.test.js
@@ -0,0 +1,198 @@
+'use strict';
+
+const assert = require('assert');
+const Kareem = require('../');
+
+describe('execPost', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('handles errors', function(done) {
+ hooks.post('cook', function(eggs, callback) {
+ callback('error!');
+ });
+
+ hooks.execPost('cook', null, [4], function(error, eggs) {
+ assert.equal('error!', error);
+ assert.ok(!eggs);
+ done();
+ });
+ });
+
+ it('unshift', function() {
+ var f1 = function() {};
+ var f2 = function() {};
+ hooks.post('cook', f1);
+ hooks.post('cook', f2, true);
+ assert.strictEqual(hooks._posts.get('cook')[0].fn, f2);
+ assert.strictEqual(hooks._posts.get('cook')[1].fn, f1);
+ });
+
+ it('arbitrary options', function() {
+ const f1 = function() {};
+ const f2 = function() {};
+ hooks.post('cook', { foo: 'bar' }, f1);
+ hooks.post('cook', { bar: 'baz' }, f2, true);
+ assert.equal(hooks._posts.get('cook')[1].foo, 'bar');
+ assert.equal(hooks._posts.get('cook')[0].bar, 'baz');
+ });
+
+ it('throws error if no function', function() {
+ assert.throws(() => hooks.post('test'), /got "undefined"/);
+ });
+
+ it('multiple posts', function(done) {
+ hooks.post('cook', function(eggs, callback) {
+ setTimeout(
+ function() {
+ callback();
+ },
+ 5);
+ });
+
+ hooks.post('cook', function(eggs, callback) {
+ setTimeout(
+ function() {
+ callback();
+ },
+ 5);
+ });
+
+ hooks.execPost('cook', null, [4], function(error, eggs) {
+ assert.ifError(error);
+ assert.equal(4, eggs);
+ done();
+ });
+ });
+
+ it('error posts', function(done) {
+ var called = {};
+ hooks.post('cook', function(eggs, callback) {
+ called.first = true;
+ callback();
+ });
+
+ hooks.post('cook', function(eggs, callback) {
+ called.second = true;
+ callback(new Error('fail'));
+ });
+
+ hooks.post('cook', function(eggs, callback) {
+ assert.ok(false);
+ });
+
+ hooks.post('cook', function(error, eggs, callback) {
+ called.fourth = true;
+ assert.equal(error.message, 'fail');
+ callback(new Error('fourth'));
+ });
+
+ hooks.post('cook', function(error, eggs, callback) {
+ called.fifth = true;
+ assert.equal(error.message, 'fourth');
+ callback(new Error('fifth'));
+ });
+
+ hooks.execPost('cook', null, [4], function(error, eggs) {
+ assert.ok(error);
+ assert.equal(error.message, 'fifth');
+ assert.deepEqual(called, {
+ first: true,
+ second: true,
+ fourth: true,
+ fifth: true
+ });
+ done();
+ });
+ });
+
+ it('error posts with initial error', function(done) {
+ var called = {};
+
+ hooks.post('cook', function(eggs, callback) {
+ assert.ok(false);
+ });
+
+ hooks.post('cook', function(error, eggs, callback) {
+ called.second = true;
+ assert.equal(error.message, 'fail');
+ callback(new Error('second'));
+ });
+
+ hooks.post('cook', function(error, eggs, callback) {
+ called.third = true;
+ assert.equal(error.message, 'second');
+ callback(new Error('third'));
+ });
+
+ hooks.post('cook', function(error, eggs, callback) {
+ called.fourth = true;
+ assert.equal(error.message, 'third');
+ callback();
+ });
+
+ var options = { error: new Error('fail') };
+ hooks.execPost('cook', null, [4], options, function(error, eggs) {
+ assert.ok(error);
+ assert.equal(error.message, 'third');
+ assert.deepEqual(called, {
+ second: true,
+ third: true,
+ fourth: true
+ });
+ done();
+ });
+ });
+
+ it('supports returning a promise', function(done) {
+ var calledPost = 0;
+
+ hooks.post('cook', function() {
+ return new Promise(resolve => {
+ setTimeout(() => {
+ ++calledPost;
+ resolve();
+ }, 100);
+ });
+ });
+
+ hooks.execPost('cook', null, [], {}, function(error) {
+ assert.ifError(error);
+ assert.equal(calledPost, 1);
+ done();
+ });
+ });
+});
+
+describe('execPostSync', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('executes hooks synchronously', function() {
+ var execed = {};
+
+ hooks.post('cook', function() {
+ execed.first = true;
+ });
+
+ hooks.post('cook', function() {
+ execed.second = true;
+ });
+
+ hooks.execPostSync('cook', null);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ });
+
+ it('works with no hooks specified', function() {
+ assert.doesNotThrow(function() {
+ hooks.execPostSync('cook', null);
+ });
+ });
+});
diff --git a/node_modules/kareem/test/pre.test.js b/node_modules/kareem/test/pre.test.js
new file mode 100644
index 0000000..d908d67
--- /dev/null
+++ b/node_modules/kareem/test/pre.test.js
@@ -0,0 +1,320 @@
+'use strict';
+
+const assert = require('assert');
+const Kareem = require('../');
+
+describe('execPre', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('handles errors with multiple pres', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', function(done) {
+ execed.first = true;
+ done();
+ });
+
+ hooks.pre('cook', function(done) {
+ execed.second = true;
+ done('error!');
+ });
+
+ hooks.pre('cook', function(done) {
+ execed.third = true;
+ done();
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.equal('error!', err);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ done();
+ });
+ });
+
+ it('sync errors', function(done) {
+ var called = 0;
+
+ hooks.pre('cook', function(next) {
+ throw new Error('woops!');
+ });
+
+ hooks.pre('cook', function(next) {
+ ++called;
+ next();
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.equal(err.message, 'woops!');
+ assert.equal(called, 0);
+ done();
+ });
+ });
+
+ it('unshift', function() {
+ var f1 = function() {};
+ var f2 = function() {};
+ hooks.pre('cook', false, f1);
+ hooks.pre('cook', false, f2, null, true);
+ assert.strictEqual(hooks._pres.get('cook')[0].fn, f2);
+ assert.strictEqual(hooks._pres.get('cook')[1].fn, f1);
+ });
+
+ it('throws error if no function', function() {
+ assert.throws(() => hooks.pre('test'), /got "undefined"/);
+ });
+
+ it('arbitrary options', function() {
+ const f1 = function() {};
+ const f2 = function() {};
+ hooks.pre('cook', { foo: 'bar' }, f1);
+ hooks.pre('cook', { bar: 'baz' }, f2, null, true);
+ assert.equal(hooks._pres.get('cook')[1].foo, 'bar');
+ assert.equal(hooks._pres.get('cook')[0].bar, 'baz');
+ });
+
+ it('handles async errors', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.first = true;
+ setTimeout(
+ function() {
+ done('error!');
+ },
+ 5);
+
+ next();
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.second = true;
+ setTimeout(
+ function() {
+ done('other error!');
+ },
+ 10);
+
+ next();
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.equal('error!', err);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ done();
+ });
+ });
+
+ it('handles async errors in next()', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.first = true;
+ setTimeout(
+ function() {
+ done('other error!');
+ },
+ 15);
+
+ next();
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.second = true;
+ setTimeout(
+ function() {
+ next('error!');
+ done('another error!');
+ },
+ 5);
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.equal('error!', err);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ done();
+ });
+ });
+
+ it('handles async errors in next() when already done', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.first = true;
+ setTimeout(
+ function() {
+ done('other error!');
+ },
+ 5);
+
+ next();
+ });
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.second = true;
+ setTimeout(
+ function() {
+ next('error!');
+ done('another error!');
+ },
+ 25);
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.equal('other error!', err);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ done();
+ });
+ });
+
+ it('async pres with clone()', function(done) {
+ var execed = false;
+
+ hooks.pre('cook', true, function(next, done) {
+ execed = true;
+ setTimeout(
+ function() {
+ done();
+ },
+ 5);
+
+ next();
+ });
+
+ hooks.clone().execPre('cook', null, function(err) {
+ assert.ifError(err);
+ assert.ok(execed);
+ done();
+ });
+ });
+
+ it('returns correct error when async pre errors', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.first = true;
+ setTimeout(
+ function() {
+ done('other error!');
+ },
+ 5);
+
+ next();
+ });
+
+ hooks.pre('cook', function(next) {
+ execed.second = true;
+ setTimeout(
+ function() {
+ next('error!');
+ },
+ 15);
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.equal('other error!', err);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ done();
+ });
+ });
+
+ it('lets async pres run when fully sync pres are done', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', true, function(next, done) {
+ execed.first = true;
+ setTimeout(
+ function() {
+ done();
+ },
+ 5);
+
+ next();
+ });
+
+ hooks.pre('cook', function() {
+ execed.second = true;
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.ifError(err);
+ assert.equal(2, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ done();
+ });
+ });
+
+ it('allows passing arguments to the next pre', function(done) {
+ var execed = {};
+
+ hooks.pre('cook', function(next) {
+ execed.first = true;
+ next(null, 'test');
+ });
+
+ hooks.pre('cook', function(next, p) {
+ execed.second = true;
+ assert.equal(p, 'test');
+ next();
+ });
+
+ hooks.pre('cook', function(next, p) {
+ execed.third = true;
+ assert.ok(!p);
+ next();
+ });
+
+ hooks.execPre('cook', null, function(err) {
+ assert.ifError(err);
+ assert.equal(3, Object.keys(execed).length);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ assert.ok(execed.third);
+ done();
+ });
+ });
+});
+
+describe('execPreSync', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('executes hooks synchronously', function() {
+ var execed = {};
+
+ hooks.pre('cook', function() {
+ execed.first = true;
+ });
+
+ hooks.pre('cook', function() {
+ execed.second = true;
+ });
+
+ hooks.execPreSync('cook', null);
+ assert.ok(execed.first);
+ assert.ok(execed.second);
+ });
+
+ it('works with no hooks specified', function() {
+ assert.doesNotThrow(function() {
+ hooks.execPreSync('cook', null);
+ });
+ });
+});
diff --git a/node_modules/kareem/test/wrap.test.js b/node_modules/kareem/test/wrap.test.js
new file mode 100644
index 0000000..dd9196e
--- /dev/null
+++ b/node_modules/kareem/test/wrap.test.js
@@ -0,0 +1,342 @@
+var assert = require('assert');
+var Kareem = require('../');
+
+describe('wrap()', function() {
+ var hooks;
+
+ beforeEach(function() {
+ hooks = new Kareem();
+ });
+
+ it('handles pre errors', function(done) {
+ hooks.pre('cook', function(done) {
+ done('error!');
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [obj];
+ args.push(function(error, result) {
+ assert.equal('error!', error);
+ assert.ok(!result);
+ assert.equal(undefined, obj.tofu);
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(o, callback) {
+ // Should never get called
+ assert.ok(false);
+ callback(null, o);
+ },
+ obj,
+ args);
+ });
+
+ it('handles pre errors when no callback defined', function(done) {
+ hooks.pre('cook', function(done) {
+ done('error!');
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [obj];
+
+ hooks.wrap(
+ 'cook',
+ function(o, callback) {
+ // Should never get called
+ assert.ok(false);
+ callback(null, o);
+ },
+ obj,
+ args);
+
+ setTimeout(
+ function() {
+ done();
+ },
+ 25);
+ });
+
+ it('handles errors in wrapped function', function(done) {
+ hooks.pre('cook', function(done) {
+ done();
+ });
+
+ hooks.post('cook', function(obj) {
+ obj.tofu = 'no';
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [obj];
+ args.push(function(error, result) {
+ assert.equal('error!', error);
+ assert.ok(!result);
+ assert.equal(undefined, obj.tofu);
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(o, callback) {
+ callback('error!');
+ },
+ obj,
+ args);
+ });
+
+ it('handles errors in post', function(done) {
+ hooks.pre('cook', function(done) {
+ done();
+ });
+
+ hooks.post('cook', function(obj, callback) {
+ obj.tofu = 'no';
+ callback('error!');
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [obj];
+ args.push(function(error, result) {
+ assert.equal('error!', error);
+ assert.ok(!result);
+ assert.equal('no', obj.tofu);
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(o, callback) {
+ callback(null, o);
+ },
+ obj,
+ args);
+ });
+
+ it('defers errors to post hooks if enabled', function(done) {
+ hooks.pre('cook', function(done) {
+ done(new Error('fail'));
+ });
+
+ hooks.post('cook', function(error, res, callback) {
+ callback(new Error('another error occurred'));
+ });
+
+ var args = [];
+ args.push(function(error) {
+ assert.equal(error.message, 'another error occurred');
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ assert.ok(false);
+ callback();
+ },
+ null,
+ args,
+ { useErrorHandlers: true, numCallbackParams: 1 });
+ });
+
+ it('error handlers with no callback', function(done) {
+ hooks.pre('cook', function(done) {
+ done(new Error('fail'));
+ });
+
+ hooks.post('cook', function(error, callback) {
+ assert.equal(error.message, 'fail');
+ done();
+ });
+
+ var args = [];
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ assert.ok(false);
+ callback();
+ },
+ null,
+ args,
+ { useErrorHandlers: true });
+ });
+
+ it('error handlers with no error', function(done) {
+ hooks.post('cook', function(error, callback) {
+ callback(new Error('another error occurred'));
+ });
+
+ var args = [];
+ args.push(function(error) {
+ assert.ifError(error);
+ done();
+ });
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ callback();
+ },
+ null,
+ args,
+ { useErrorHandlers: true });
+ });
+
+ it('works with no args', function(done) {
+ hooks.pre('cook', function(done) {
+ done();
+ });
+
+ hooks.post('cook', function(callback) {
+ obj.tofu = 'no';
+ callback();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [];
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ callback(null);
+ },
+ obj,
+ args);
+
+ setTimeout(
+ function() {
+ assert.equal('no', obj.tofu);
+ done();
+ },
+ 25);
+ });
+
+ it('handles pre errors with no args', function(done) {
+ hooks.pre('cook', function(done) {
+ done('error!');
+ });
+
+ hooks.post('cook', function(callback) {
+ obj.tofu = 'no';
+ callback();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [];
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ callback(null);
+ },
+ obj,
+ args);
+
+ setTimeout(
+ function() {
+ assert.equal(undefined, obj.tofu);
+ done();
+ },
+ 25);
+ });
+
+ it('handles wrapped function errors with no args', function(done) {
+ hooks.pre('cook', function(done) {
+ obj.waffles = false;
+ done();
+ });
+
+ hooks.post('cook', function(callback) {
+ obj.tofu = 'no';
+ callback();
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [];
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ callback('error!');
+ },
+ obj,
+ args);
+
+ setTimeout(
+ function() {
+ assert.equal(false, obj.waffles);
+ assert.equal(undefined, obj.tofu);
+ done();
+ },
+ 25);
+ });
+
+ it('handles post errors with no args', function(done) {
+ hooks.pre('cook', function(done) {
+ obj.waffles = false;
+ done();
+ });
+
+ hooks.post('cook', function(callback) {
+ obj.tofu = 'no';
+ callback('error!');
+ });
+
+ var obj = { bacon: 0, eggs: 0 };
+
+ var args = [];
+
+ hooks.wrap(
+ 'cook',
+ function(callback) {
+ callback();
+ },
+ obj,
+ args);
+
+ setTimeout(
+ function() {
+ assert.equal(false, obj.waffles);
+ assert.equal('no', obj.tofu);
+ done();
+ },
+ 25);
+ });
+
+ it('sync wrappers', function() {
+ var calledPre = 0;
+ var calledFn = 0;
+ var calledPost = 0;
+ hooks.pre('cook', function() {
+ ++calledPre;
+ });
+
+ hooks.post('cook', function() {
+ ++calledPost;
+ });
+
+ var wrapper = hooks.createWrapperSync('cook', function() { ++calledFn; });
+
+ wrapper();
+
+ assert.equal(calledPre, 1);
+ assert.equal(calledFn, 1);
+ assert.equal(calledPost, 1);
+ });
+});