Demo for query storing
Change-Id: I947bcac841992c3f6cfd01ab337c265b0d01cb70
diff --git a/node_modules/hooker/LICENSE-MIT b/node_modules/hooker/LICENSE-MIT
new file mode 100644
index 0000000..90c336c
--- /dev/null
+++ b/node_modules/hooker/LICENSE-MIT
@@ -0,0 +1,22 @@
+Copyright (c) 2012 "Cowboy" Ben Alman
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
diff --git a/node_modules/hooker/README.md b/node_modules/hooker/README.md
new file mode 100644
index 0000000..138943a
--- /dev/null
+++ b/node_modules/hooker/README.md
@@ -0,0 +1,186 @@
+# JavaScript Hooker
+
+Monkey-patch (hook) functions for debugging and stuff.
+
+## Getting Started
+
+This code should work just fine in Node.js:
+
+First, install the module with: `npm install hooker`
+
+```javascript
+var hooker = require('hooker');
+hooker.hook(Math, "max", function() {
+ console.log(arguments.length + " arguments passed");
+});
+Math.max(5, 6, 7) // logs: "3 arguments passed", returns 7
+```
+
+Or in the browser:
+
+```html
+<script src="dist/ba-hooker.min.js"></script>
+<script>
+hook(Math, "max", function() {
+ console.log(arguments.length + " arguments passed");
+});
+Math.max(5, 6, 7) // logs: "3 arguments passed", returns 7
+</script>
+```
+
+In the browser, you can attach Hooker's methods to any object.
+
+```html
+<script>
+this.exports = Bocoup.utils;
+</script>
+<script src="dist/ba-hooker.min.js"></script>
+<script>
+Bocoup.utils.hook(Math, "max", function() {
+ console.log(arguments.length + " arguments passed");
+});
+Math.max(5, 6, 7) // logs: "3 arguments passed", returns 7
+</script>
+```
+
+## Documentation
+
+### hooker.hook
+Monkey-patch (hook) one or more methods of an object.
+#### Signature:
+`hooker.hook(object, [ props, ] [options | prehookFunction])`
+#### `props`
+The optional `props` argument can be a method name, array of method names or null. If null (or omitted), all enumerable methods of `object` will be hooked.
+#### `options`
+* `pre` - (Function) a pre-hook function to be executed before the original function. Arguments passed into the method will be passed into the pre-hook function as well.
+* `post` - (Function) a post-hook function to be executed after the original function. The original function's result is passed into the post-hook function as its first argument, followed by the method arguments.
+* `once` - (Boolean) if true, auto-unhook the function after the first execution.
+* `passName` - (Boolean) if true, pass the name of the method into the pre-hook function as its first arg (preceding all other arguments), and into the post-hook function as the second arg (after result but preceding all other arguments).
+
+#### Returns:
+An array of hooked method names.
+
+### hooker.unhook
+Un-monkey-patch (unhook) one or more methods of an object.
+#### Signature:
+`hooker.unhook(object [, props ])`
+#### `props`
+The optional `props` argument can be a method name, array of method names or null. If null (or omitted), all methods of `object` will be unhooked.
+#### Returns:
+An array of unhooked method names.
+
+### hooker.orig
+Get a reference to the original method from a hooked function.
+#### Signature:
+`hooker.orig(object, props)`
+
+### hooker.override
+When a pre- or post-hook returns the result of this function, the value
+passed will be used in place of the original function's return value. Any
+post-hook override value will take precedence over a pre-hook override value.
+#### Signature:
+`hooker.override(value)`
+
+### hooker.preempt
+When a pre-hook returns the result of this function, the value passed will
+be used in place of the original function's return value, and the original
+function will NOT be executed.
+#### Signature:
+`hooker.preempt(value)`
+
+### hooker.filter
+When a pre-hook returns the result of this function, the context and
+arguments passed will be applied into the original function.
+#### Signature:
+`hooker.filter(context, arguments)`
+
+
+## Examples
+See the unit tests for more examples.
+
+```javascript
+var hooker = require('hooker');
+// Simple logging.
+hooker.hook(Math, "max", function() {
+ console.log(arguments.length + " arguments passed");
+});
+Math.max(5, 6, 7) // logs: "3 arguments passed", returns 7
+
+hooker.unhook(Math, "max"); // (This is assumed between all further examples)
+Math.max(5, 6, 7) // 7
+
+// Returning hooker.override(value) overrides the original value.
+hooker.hook(Math, "max", function() {
+ if (arguments.length === 0) {
+ return hooker.override(9000);
+ }
+});
+Math.max(5, 6, 7) // 7
+Math.max() // 9000
+
+// Auto-unhook after one execution.
+hooker.hook(Math, "max", {
+ once: true,
+ pre: function() {
+ console.log("Init something here");
+ }
+});
+Math.max(5, 6, 7) // logs: "Init something here", returns 7
+Math.max(5, 6, 7) // 7
+
+// Filter `this` and arguments through a pre-hook function.
+hooker.hook(Math, "max", {
+ pre: function() {
+ var args = [].map.call(arguments, function(num) {
+ return num * 2;
+ });
+ return hooker.filter(this, args); // thisValue, arguments
+ }
+});
+Math.max(5, 6, 7) // 14
+
+// Modify the original function's result with a post-hook function.
+hooker.hook(Math, "max", {
+ post: function(result) {
+ return hooker.override(result * 100);
+ }
+});
+Math.max(5, 6, 7) // 700
+
+// Hook every Math method. Note: if Math's methods were enumerable, the second
+// argument could be omitted. Since they aren't, an array of properties to hook
+// must be explicitly passed. Non-method properties will be skipped.
+// See a more generic example here: http://bit.ly/vvJlrS
+hooker.hook(Math, Object.getOwnPropertyNames(Math), {
+ passName: true,
+ pre: function(name) {
+ console.log("=> Math." + name, [].slice.call(arguments, 1));
+ },
+ post: function(result, name) {
+ console.log("<= Math." + name, result);
+ }
+});
+
+var result = Math.max(5, 6, 7);
+// => Math.max [ 5, 6, 7 ]
+// <= Math.max 7
+result // 7
+
+result = Math.ceil(3.456);
+// => Math.ceil [ 3.456 ]
+// <= Math.ceil 4
+result // 4
+```
+
+## Contributing
+In lieu of a formal styleguide, take care to maintain the existing coding style. Add unit tests for any new or changed functionality. Lint and test your code using [grunt](https://github.com/cowboy/grunt).
+
+_Also, please don't edit files in the "dist" subdirectory as they are generated via grunt. You'll find source code in the "lib" subdirectory!_
+
+## Release History
+2012/01/09 - v0.2.3 - First official release.
+
+## License
+Copyright (c) 2012 "Cowboy" Ben Alman
+Licensed under the MIT license.
+<http://benalman.com/about/license/>
diff --git a/node_modules/hooker/child.js b/node_modules/hooker/child.js
new file mode 100644
index 0000000..ae7dcf2
--- /dev/null
+++ b/node_modules/hooker/child.js
@@ -0,0 +1,101 @@
+var path = require('path');
+var fs = require('fs');
+var nodeunit = require('nodeunit');
+
+var filepaths = fs.readdirSync('test').map(function(filename) {
+ return path.join('test', filename);
+});
+
+var unfinished = {};
+var currentModule;
+function sendMessage(message) {
+ process.stdout.write(JSON.stringify(message) + '\n');
+}
+
+// If an exception is thrown, let the parent process know and exit.
+process.on('uncaughtException', function (e) {
+ sendMessage({error: [e.name, e.message, e.stack]});
+ process.exit();
+});
+
+// If Nodeunit explodes because a test was missing test.done(), handle it.
+var unfinished = {};
+process.on('exit', function (e) {
+ var len = Object.keys(unfinished).length
+ if (len > 0) {
+ sendMessage({exit: ['UNFINISHED']});
+ // process.reallyExit(len);
+ } else {
+ sendMessage({exit: ['finished']});
+ }
+ // process.exit();
+});
+
+nodeunit.reporters.test = {
+ run: function(files, options, callback) {
+ // Nodeunit needs absolute paths.
+ var paths = files.map(function (filepath) {
+ return path.resolve(filepath);
+ });
+ nodeunit.runFiles(paths, {
+ // No idea.
+ testspec: undefined,
+ // Executed when the first test in a file is run. If no tests exist in
+ // the file, this doesn't execute.
+ moduleStart: function(name) {
+ // Keep track of this so that moduleDone output can be suppressed in
+ // cases where a test file contains no tests.
+ currentModule = name;
+ // Send back to the parent process.
+ sendMessage({moduleStart: [name.toString()]});
+ },
+ // Executed after a file is done being processed. This executes whether
+ // tests exist in the file or not.
+ moduleDone: function(name) {
+ // Abort if no tests actually ran.
+ if (name !== currentModule) { return; }
+ // Send back to the parent process.
+ sendMessage({moduleDone: [name.toString()]});
+ },
+ // Executed before each test is run.
+ testStart: function(name) {
+ // Keep track of the current test, in case test.done() was omitted
+ // and Nodeunit explodes.
+ unfinished[name] = name;
+ // Send back to the parent process.
+ sendMessage({testStart: [name.toString()]});
+ },
+ // Executed after each test and all its assertions are run.
+ testDone: function(name, assertions) {
+ delete unfinished[name];
+ // Send back to the parent process.
+ sendMessage({testDone: [
+ name.toString(),
+ assertions.failures(),
+ assertions.map(function(assertion) {
+ var e = assertion.error;
+ if (e) {
+ assertion.error = {
+ name: e.name,
+ message: e.message,
+ stack: e.stack
+ };
+ }
+ return assertion;
+ })
+ ]});
+ },
+ // Executed when everything is all done.
+ done: function (assertions) {
+ // Send back to the parent process.
+ sendMessage({done: [
+ assertions.failures(),
+ assertions.duration,
+ assertions
+ ]});
+ }
+ });
+ }
+}
+
+nodeunit.reporters.test.run(filepaths, {});
diff --git a/node_modules/hooker/dist/ba-hooker.js b/node_modules/hooker/dist/ba-hooker.js
new file mode 100644
index 0000000..d10a321
--- /dev/null
+++ b/node_modules/hooker/dist/ba-hooker.js
@@ -0,0 +1,169 @@
+/*! JavaScript Hooker - v0.2.3 - 1/29/2012
+* http://github.com/cowboy/javascript-hooker
+* Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */
+
+(function(exports) {
+ // Get an array from an array-like object with slice.call(arrayLikeObject).
+ var slice = [].slice;
+ // Get an "[object [[Class]]]" string with toString.call(value).
+ var toString = {}.toString;
+
+ // I can't think of a better way to ensure a value is a specific type other
+ // than to create instances and use the `instanceof` operator.
+ function HookerOverride(v) { this.value = v; }
+ function HookerPreempt(v) { this.value = v; }
+ function HookerFilter(c, a) { this.context = c; this.args = a; }
+
+ // When a pre- or post-hook returns the result of this function, the value
+ // passed will be used in place of the original function's return value. Any
+ // post-hook override value will take precedence over a pre-hook override
+ // value.
+ exports.override = function(value) {
+ return new HookerOverride(value);
+ };
+
+ // When a pre-hook returns the result of this function, the value passed will
+ // be used in place of the original function's return value, and the original
+ // function will NOT be executed.
+ exports.preempt = function(value) {
+ return new HookerPreempt(value);
+ };
+
+ // When a pre-hook returns the result of this function, the context and
+ // arguments passed will be applied into the original function.
+ exports.filter = function(context, args) {
+ return new HookerFilter(context, args);
+ };
+
+ // Execute callback(s) for properties of the specified object.
+ function forMethods(obj, props, callback) {
+ var prop;
+ if (typeof props === "string") {
+ // A single prop string was passed. Create an array.
+ props = [props];
+ } else if (props == null) {
+ // No props were passed, so iterate over all properties, building an
+ // array. Unfortunately, Object.keys(obj) doesn't work everywhere yet, so
+ // this has to be done manually.
+ props = [];
+ for (prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ props.push(prop);
+ }
+ }
+ }
+ // Execute callback for every method in the props array.
+ var i = props.length;
+ while (i--) {
+ // If the property isn't a function...
+ if (toString.call(obj[props[i]]) !== "[object Function]" ||
+ // ...or the callback returns false...
+ callback(obj, props[i]) === false) {
+ // ...remove it from the props array to be returned.
+ props.splice(i, 1);
+ }
+ }
+ // Return an array of method names for which the callback didn't fail.
+ return props;
+ }
+
+ // Monkey-patch (hook) a method of an object.
+ exports.hook = function(obj, props, options) {
+ // If the props argument was omitted, shuffle the arguments.
+ if (options == null) {
+ options = props;
+ props = null;
+ }
+ // If just a function is passed instead of an options hash, use that as a
+ // pre-hook function.
+ if (typeof options === "function") {
+ options = {pre: options};
+ }
+
+ // Hook the specified method of the object.
+ return forMethods(obj, props, function(obj, prop) {
+ // The original (current) method.
+ var orig = obj[prop];
+ // The new hooked function.
+ function hooked() {
+ var result, origResult, tmp;
+
+ // Get an array of arguments.
+ var args = slice.call(arguments);
+
+ // If passName option is specified, prepend prop to the args array,
+ // passing it as the first argument to any specified hook functions.
+ if (options.passName) {
+ args.unshift(prop);
+ }
+
+ // If a pre-hook function was specified, invoke it in the current
+ // context with the passed-in arguments, and store its result.
+ if (options.pre) {
+ result = options.pre.apply(this, args);
+ }
+
+ if (result instanceof HookerFilter) {
+ // If the pre-hook returned hooker.filter(context, args), invoke the
+ // original function with that context and arguments, and store its
+ // result.
+ origResult = result = orig.apply(result.context, result.args);
+ } else if (result instanceof HookerPreempt) {
+ // If the pre-hook returned hooker.preempt(value) just use the passed
+ // value and don't execute the original function.
+ origResult = result = result.value;
+ } else {
+ // Invoke the original function in the current context with the
+ // passed-in arguments, and store its result.
+ origResult = orig.apply(this, arguments);
+ // If the pre-hook returned hooker.override(value), use the passed
+ // value, otherwise use the original function's result.
+ result = result instanceof HookerOverride ? result.value : origResult;
+ }
+
+ if (options.post) {
+ // If a post-hook function was specified, invoke it in the current
+ // context, passing in the result of the original function as the
+ // first argument, followed by any passed-in arguments.
+ tmp = options.post.apply(this, [origResult].concat(args));
+ if (tmp instanceof HookerOverride) {
+ // If the post-hook returned hooker.override(value), use the passed
+ // value, otherwise use the previously computed result.
+ result = tmp.value;
+ }
+ }
+
+ // Unhook if the "once" option was specified.
+ if (options.once) {
+ exports.unhook(obj, prop);
+ }
+
+ // Return the result!
+ return result;
+ }
+ // Re-define the method.
+ obj[prop] = hooked;
+ // Fail if the function couldn't be hooked.
+ if (obj[prop] !== hooked) { return false; }
+ // Store a reference to the original method as a property on the new one.
+ obj[prop]._orig = orig;
+ });
+ };
+
+ // Get a reference to the original method from a hooked function.
+ exports.orig = function(obj, prop) {
+ return obj[prop]._orig;
+ };
+
+ // Un-monkey-patch (unhook) a method of an object.
+ exports.unhook = function(obj, props) {
+ return forMethods(obj, props, function(obj, prop) {
+ // Get a reference to the original method, if it exists.
+ var orig = exports.orig(obj, prop);
+ // If there's no original method, it can't be unhooked, so fail.
+ if (!orig) { return false; }
+ // Unhook the method.
+ obj[prop] = orig;
+ });
+ };
+}(typeof exports === "object" && exports || this));
diff --git a/node_modules/hooker/dist/ba-hooker.min.js b/node_modules/hooker/dist/ba-hooker.min.js
new file mode 100644
index 0000000..2bcdb54
--- /dev/null
+++ b/node_modules/hooker/dist/ba-hooker.min.js
@@ -0,0 +1,4 @@
+/*! JavaScript Hooker - v0.2.3 - 1/29/2012
+* http://github.com/cowboy/javascript-hooker
+* Copyright (c) 2012 "Cowboy" Ben Alman; Licensed MIT */
+(function(a){function d(a){this.value=a}function e(a){this.value=a}function f(a,b){this.context=a,this.args=b}function g(a,b,d){var e;if(typeof b=="string")b=[b];else if(b==null){b=[];for(e in a)a.hasOwnProperty(e)&&b.push(e)}var f=b.length;while(f--)(c.call(a[b[f]])!=="[object Function]"||d(a,b[f])===!1)&&b.splice(f,1);return b}var b=[].slice,c={}.toString;a.override=function(a){return new d(a)},a.preempt=function(a){return new e(a)},a.filter=function(a,b){return new f(a,b)},a.hook=function(c,h,i){return i==null&&(i=h,h=null),typeof i=="function"&&(i={pre:i}),g(c,h,function(c,g){function j(){var j,k,l,m=b.call(arguments);return i.passName&&m.unshift(g),i.pre&&(j=i.pre.apply(this,m)),j instanceof f?k=j=h.apply(j.context,j.args):j instanceof e?k=j=j.value:(k=h.apply(this,arguments),j=j instanceof d?j.value:k),i.post&&(l=i.post.apply(this,[k].concat(m)),l instanceof d&&(j=l.value)),i.once&&a.unhook(c,g),j}var h=c[g];c[g]=j;if(c[g]!==j)return!1;c[g]._orig=h})},a.orig=function(a,b){return a[b]._orig},a.unhook=function(b,c){return g(b,c,function(b,c){var d=a.orig(b,c);if(!d)return!1;b[c]=d})}})(typeof exports=="object"&&exports||this)
\ No newline at end of file
diff --git a/node_modules/hooker/grunt.js b/node_modules/hooker/grunt.js
new file mode 100644
index 0000000..c695148
--- /dev/null
+++ b/node_modules/hooker/grunt.js
@@ -0,0 +1,47 @@
+/*global config:true, task:true*/
+config.init({
+ pkg: '<json:package.json>',
+ meta: {
+ name: 'JavaScript Hooker',
+ banner: '/*! <%= meta.name %> - v<%= pkg.version %> - <%= template.today("m/d/yyyy") %>\n' +
+ '* <%= pkg.homepage %>\n' +
+ '* Copyright (c) <%= template.today("yyyy") %> <%= pkg.author.name %>;' +
+ ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */'
+ },
+ concat: {
+ 'dist/ba-hooker.js': ['<banner>', '<file_strip_banner:lib/hooker.js>']
+ },
+ min: {
+ 'dist/ba-hooker.min.js': ['<banner>', 'dist/ba-hooker.js']
+ },
+ test: {
+ files: ['test/**/*.js']
+ },
+ lint: {
+ files: ['grunt.js', 'lib/**/*.js', 'test/**/*.js']
+ },
+ watch: {
+ files: '<config:lint.files>',
+ tasks: 'lint:files test:files'
+ },
+ jshint: {
+ options: {
+ curly: true,
+ eqeqeq: true,
+ immed: true,
+ latedef: true,
+ newcap: true,
+ noarg: true,
+ sub: true,
+ undef: true,
+ eqnull: true
+ },
+ globals: {
+ exports: true
+ }
+ },
+ uglify: {}
+});
+
+// Default task.
+task.registerTask('default', 'lint:files test:files concat min');
diff --git a/node_modules/hooker/lib/hooker.js b/node_modules/hooker/lib/hooker.js
new file mode 100644
index 0000000..1ff9764
--- /dev/null
+++ b/node_modules/hooker/lib/hooker.js
@@ -0,0 +1,174 @@
+/*
+ * JavaScript Hooker
+ * http://github.com/cowboy/javascript-hooker
+ *
+ * Copyright (c) 2012 "Cowboy" Ben Alman
+ * Licensed under the MIT license.
+ * http://benalman.com/about/license/
+ */
+
+(function(exports) {
+ // Get an array from an array-like object with slice.call(arrayLikeObject).
+ var slice = [].slice;
+ // Get an "[object [[Class]]]" string with toString.call(value).
+ var toString = {}.toString;
+
+ // I can't think of a better way to ensure a value is a specific type other
+ // than to create instances and use the `instanceof` operator.
+ function HookerOverride(v) { this.value = v; }
+ function HookerPreempt(v) { this.value = v; }
+ function HookerFilter(c, a) { this.context = c; this.args = a; }
+
+ // When a pre- or post-hook returns the result of this function, the value
+ // passed will be used in place of the original function's return value. Any
+ // post-hook override value will take precedence over a pre-hook override
+ // value.
+ exports.override = function(value) {
+ return new HookerOverride(value);
+ };
+
+ // When a pre-hook returns the result of this function, the value passed will
+ // be used in place of the original function's return value, and the original
+ // function will NOT be executed.
+ exports.preempt = function(value) {
+ return new HookerPreempt(value);
+ };
+
+ // When a pre-hook returns the result of this function, the context and
+ // arguments passed will be applied into the original function.
+ exports.filter = function(context, args) {
+ return new HookerFilter(context, args);
+ };
+
+ // Execute callback(s) for properties of the specified object.
+ function forMethods(obj, props, callback) {
+ var prop;
+ if (typeof props === "string") {
+ // A single prop string was passed. Create an array.
+ props = [props];
+ } else if (props == null) {
+ // No props were passed, so iterate over all properties, building an
+ // array. Unfortunately, Object.keys(obj) doesn't work everywhere yet, so
+ // this has to be done manually.
+ props = [];
+ for (prop in obj) {
+ if (obj.hasOwnProperty(prop)) {
+ props.push(prop);
+ }
+ }
+ }
+ // Execute callback for every method in the props array.
+ var i = props.length;
+ while (i--) {
+ // If the property isn't a function...
+ if (toString.call(obj[props[i]]) !== "[object Function]" ||
+ // ...or the callback returns false...
+ callback(obj, props[i]) === false) {
+ // ...remove it from the props array to be returned.
+ props.splice(i, 1);
+ }
+ }
+ // Return an array of method names for which the callback didn't fail.
+ return props;
+ }
+
+ // Monkey-patch (hook) a method of an object.
+ exports.hook = function(obj, props, options) {
+ // If the props argument was omitted, shuffle the arguments.
+ if (options == null) {
+ options = props;
+ props = null;
+ }
+ // If just a function is passed instead of an options hash, use that as a
+ // pre-hook function.
+ if (typeof options === "function") {
+ options = {pre: options};
+ }
+
+ // Hook the specified method of the object.
+ return forMethods(obj, props, function(obj, prop) {
+ // The original (current) method.
+ var orig = obj[prop];
+ // The new hooked function.
+ function hooked() {
+ var result, origResult, tmp;
+
+ // Get an array of arguments.
+ var args = slice.call(arguments);
+
+ // If passName option is specified, prepend prop to the args array,
+ // passing it as the first argument to any specified hook functions.
+ if (options.passName) {
+ args.unshift(prop);
+ }
+
+ // If a pre-hook function was specified, invoke it in the current
+ // context with the passed-in arguments, and store its result.
+ if (options.pre) {
+ result = options.pre.apply(this, args);
+ }
+
+ if (result instanceof HookerFilter) {
+ // If the pre-hook returned hooker.filter(context, args), invoke the
+ // original function with that context and arguments, and store its
+ // result.
+ origResult = result = orig.apply(result.context, result.args);
+ } else if (result instanceof HookerPreempt) {
+ // If the pre-hook returned hooker.preempt(value) just use the passed
+ // value and don't execute the original function.
+ origResult = result = result.value;
+ } else {
+ // Invoke the original function in the current context with the
+ // passed-in arguments, and store its result.
+ origResult = orig.apply(this, arguments);
+ // If the pre-hook returned hooker.override(value), use the passed
+ // value, otherwise use the original function's result.
+ result = result instanceof HookerOverride ? result.value : origResult;
+ }
+
+ if (options.post) {
+ // If a post-hook function was specified, invoke it in the current
+ // context, passing in the result of the original function as the
+ // first argument, followed by any passed-in arguments.
+ tmp = options.post.apply(this, [origResult].concat(args));
+ if (tmp instanceof HookerOverride) {
+ // If the post-hook returned hooker.override(value), use the passed
+ // value, otherwise use the previously computed result.
+ result = tmp.value;
+ }
+ }
+
+ // Unhook if the "once" option was specified.
+ if (options.once) {
+ exports.unhook(obj, prop);
+ }
+
+ // Return the result!
+ return result;
+ }
+ // Re-define the method.
+ obj[prop] = hooked;
+ // Fail if the function couldn't be hooked.
+ if (obj[prop] !== hooked) { return false; }
+ // Store a reference to the original method as a property on the new one.
+ obj[prop]._orig = orig;
+ });
+ };
+
+ // Get a reference to the original method from a hooked function.
+ exports.orig = function(obj, prop) {
+ return obj[prop]._orig;
+ };
+
+ // Un-monkey-patch (unhook) a method of an object.
+ exports.unhook = function(obj, props) {
+ return forMethods(obj, props, function(obj, prop) {
+ // Get a reference to the original method, if it exists.
+ var orig = exports.orig(obj, prop);
+ // If there's no original method, it can't be unhooked, so fail.
+ if (!orig) { return false; }
+ // Unhook the method.
+ obj[prop] = orig;
+ });
+ };
+}(typeof exports === "object" && exports || this));
diff --git a/node_modules/hooker/package.json b/node_modules/hooker/package.json
new file mode 100644
index 0000000..21649bc
--- /dev/null
+++ b/node_modules/hooker/package.json
@@ -0,0 +1,67 @@
+{
+ "_from": "hooker@~0.2.3",
+ "_id": "hooker@0.2.3",
+ "_inBundle": false,
+ "_integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=",
+ "_location": "/hooker",
+ "_phantomChildren": {},
+ "_requested": {
+ "type": "range",
+ "registry": true,
+ "raw": "hooker@~0.2.3",
+ "name": "hooker",
+ "escapedName": "hooker",
+ "rawSpec": "~0.2.3",
+ "saveSpec": null,
+ "fetchSpec": "~0.2.3"
+ },
+ "_requiredBy": [
+ "/grunt-legacy-log",
+ "/grunt-legacy-util"
+ ],
+ "_resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz",
+ "_shasum": "b834f723cc4a242aa65963459df6d984c5d3d959",
+ "_spec": "hooker@~0.2.3",
+ "_where": "C:\\Users\\marcr\\Desktop\\KorAp\\Git\\Kalamar\\node_modules\\grunt-legacy-log",
+ "author": {
+ "name": "\"Cowboy\" Ben Alman",
+ "url": "http://benalman.com/"
+ },
+ "bugs": {
+ "url": "https://github.com/cowboy/javascript-hooker/issues"
+ },
+ "bundleDependencies": false,
+ "dependencies": {},
+ "deprecated": false,
+ "description": "Monkey-patch (hook) functions for debugging and stuff.",
+ "devDependencies": {
+ "grunt": "~0.2.1"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "homepage": "http://github.com/cowboy/javascript-hooker",
+ "keywords": [
+ "patch",
+ "hook",
+ "function",
+ "debug",
+ "aop"
+ ],
+ "licenses": [
+ {
+ "type": "MIT",
+ "url": "https://github.com/cowboy/javascript-hooker/blob/master/LICENSE-MIT"
+ }
+ ],
+ "main": "lib/hooker",
+ "name": "hooker",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/cowboy/javascript-hooker.git"
+ },
+ "scripts": {
+ "test": "grunt test"
+ },
+ "version": "0.2.3"
+}
diff --git a/node_modules/hooker/parent.js b/node_modules/hooker/parent.js
new file mode 100644
index 0000000..c4a055e
--- /dev/null
+++ b/node_modules/hooker/parent.js
@@ -0,0 +1,17 @@
+var spawn = require('child_process').spawn;
+
+function loop() {
+ console.log('starting');
+ console.log(this);
+ //var child = spawn('./node_modules/nodeunit/bin/nodeunit', ['test']);
+ var child = spawn('node', ['child.js']);
+ child.stdout.on('data', function(buffer) {
+ process.stdout.write(buffer);
+ });
+ child.on('exit', this.async());
+}
+
+var context = {
+ async: function() { return loop.bind(context); }
+};
+loop.call(context);
\ No newline at end of file
diff --git a/node_modules/hooker/test/hooker_test.js b/node_modules/hooker/test/hooker_test.js
new file mode 100644
index 0000000..dc5910a
--- /dev/null
+++ b/node_modules/hooker/test/hooker_test.js
@@ -0,0 +1,435 @@
+/*global require:true */
+var hooker = require('../lib/hooker');
+
+exports['hook'] = {
+ setUp: function(done) {
+ this.order = [];
+ this.track = function() {
+ [].push.apply(this.order, arguments);
+ };
+
+ this.prop = 1;
+ this.add = function(a, b) {
+ this.track("add", this.prop, a, b);
+ return this.prop + a + b;
+ };
+
+ this.obj = {
+ that: this,
+ prop: 1,
+ add1: function(a, b) {
+ this.that.track("add1", this.prop, a, b);
+ return this.prop + a + b;
+ },
+ add2: function(a, b) {
+ this.that.track("add2", this.prop, a, b);
+ return this.prop + a + b;
+ },
+ add3: function(a, b) {
+ this.that.track("add3", this.prop, a, b);
+ return this.prop + a + b;
+ }
+ };
+
+ done();
+ },
+ 'orig': function(test) {
+ test.expect(1);
+ var orig = this.add;
+ hooker.hook(this, "add", function() {});
+ test.strictEqual(hooker.orig(this, "add"), orig, "should return a refernce to the original function.");
+ test.done();
+ },
+ 'once': function(test) {
+ test.expect(5);
+ var orig = this.add;
+ hooker.hook(this, "add", {
+ once: true,
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ }
+ });
+ test.strictEqual(this.add(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", 1, 2, 3], "functions should execute in-order.");
+ test.strictEqual(this.add, orig, "should automatically unhook when once is specified.");
+ this.order = [];
+ test.strictEqual(this.add(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["add", 1, 2, 3], "only the original function should execute.");
+ test.done();
+ },
+ 'pre-hook (simple syntax)': function(test) {
+ test.expect(3);
+ // Pre-hook.
+ var result = hooker.hook(this, "add", function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ });
+ test.deepEqual(result, ["add"], "add should have been hooked.");
+ test.strictEqual(this.add(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", 1, 2, 3], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre-hook': function(test) {
+ test.expect(3);
+ // Pre-hook.
+ var result = hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ }
+ });
+ test.deepEqual(result, ["add"], "add should have been hooked.");
+ test.strictEqual(this.add(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", 1, 2, 3], "functions should execute in-order.");
+ test.done();
+ },
+ 'post-hook': function(test) {
+ test.expect(3);
+ // Post-hook.
+ var result = hooker.hook(this, "add", {
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ }
+ });
+ test.deepEqual(result, ["add"], "add should have been hooked.");
+ test.strictEqual(this.add(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["add", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook': function(test) {
+ test.expect(2);
+ // Pre- & post-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ test.done();
+ },
+
+ 'pre-hook, return value override': function(test) {
+ test.expect(2);
+ // Pre-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // This return value will override the original function's return value.
+ return hooker.override("b" + this.prop + a + b);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "b123", "should return the overridden result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", 1, 2, 3], "functions should execute in-order.");
+ test.done();
+ },
+ 'post-hook, return value override': function(test) {
+ test.expect(2);
+ // Post-hook.
+ hooker.hook(this, "add", {
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ // This return value will override the original function's return value.
+ return hooker.override("a" + this.prop + a + b + result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "a1236", "should return the post-hook overridden result.");
+ test.deepEqual(this.order, ["add", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, return value override': function(test) {
+ test.expect(2);
+ // Pre- & post-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // This return value will override the original function's return value.
+ return hooker.override("b" + this.prop + a + b);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ // This return value will override the original function's return value
+ // AND the pre-hook's return value.
+ return hooker.override("a" + this.prop + a + b + result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "a1236", "should return the overridden result, and post-hook result should take precedence over pre-hook result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ test.done();
+ },
+
+ 'pre-hook, filtering arguments': function(test) {
+ test.expect(2);
+ // Pre-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Return hooker.filter(context, arguments) and they will be passed into
+ // the original function. The "track" and "order" propterites are just
+ // set here for the same of this unit test.
+ return hooker.filter({prop: "x", track: this.track, order: this.order}, ["y", "z"]);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "xyz", "should return the original function's result, given filtered context and arguments.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", "x", "y", "z"], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, filtering arguments': function(test) {
+ test.expect(2);
+ // Pre- & post-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Return hooker.filter(context, arguments) and they will be passed into
+ // the original function. The "track" and "order" propterites are just
+ // set here for the same of this unit test.
+ return hooker.filter({prop: "x", track: this.track, order: this.order}, ["y", "z"]);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "xyz", "should return the original function's result, given filtered context and arguments.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", "x", "y", "z", "after", 1, 2, 3, "xyz"], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, filtering arguments, return value override': function(test) {
+ test.expect(2);
+ // Pre- & post-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Return hooker.filter(context, arguments) and they will be passed into
+ // the original function. The "track" and "order" propterites are just
+ // set here for the same of this unit test.
+ return hooker.filter({prop: "x", track: this.track, order: this.order}, ["y", "z"]);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ // This return value will override the original function's return value
+ // AND the pre-hook's return value.
+ return hooker.override("a" + this.prop + a + b + result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "a123xyz", "should return the post-hook overridden result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add", "x", "y", "z", "after", 1, 2, 3, "xyz"], "functions should execute in-order.");
+ test.done();
+ },
+
+ 'pre-hook, preempt original function': function(test) {
+ test.expect(2);
+ // Pre-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Returning hooker.preempt will prevent the original function from being
+ // invoked and optionally set a return value.
+ return hooker.preempt();
+ }
+ });
+ test.strictEqual(this.add(2, 3), undefined, "should return the value passed to preempt.");
+ test.deepEqual(this.order, ["before", 1, 2, 3], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre-hook, preempt original function with value': function(test) {
+ test.expect(2);
+ // Pre-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Returning hooker.preempt will prevent the original function from being
+ // invoked and optionally set a return value.
+ return hooker.preempt(9000);
+ }
+ });
+ test.strictEqual(this.add(2, 3), 9000, "should return the value passed to preempt.");
+ test.deepEqual(this.order, ["before", 1, 2, 3], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, preempt original function with value': function(test) {
+ test.expect(2);
+ // Pre- & post-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Returning hooker.preempt will prevent the original function from being
+ // invoked and optionally set a return value.
+ return hooker.preempt(9000);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), 9000, "should return the value passed to preempt.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "after", 1, 2, 3, 9000], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, preempt original function with value, return value override': function(test) {
+ test.expect(2);
+ // Pre- & post-hook.
+ hooker.hook(this, "add", {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.track("before", this.prop, a, b);
+ // Returning hooker.preempt will prevent the original function from being
+ // invoked and optionally set a return value.
+ return hooker.preempt(9000);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.track("after", this.prop, a, b, result);
+ // This return value will override any preempt value set in pre-hook.
+ return hooker.override("a" + this.prop + a + b + result);
+ }
+ });
+ test.strictEqual(this.add(2, 3), "a1239000", "should return the overridden result, and post-hook result should take precedence over preempt value.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "after", 1, 2, 3, 9000], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, some properties': function(test) {
+ test.expect(7);
+ // Pre- & post-hook.
+ var result = hooker.hook(this.obj, ["add1", "add2"], {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.that.track("before", this.prop, a, b);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.that.track("after", this.prop, a, b, result);
+ }
+ });
+ test.deepEqual(result.sort(), ["add1", "add2"], "both functions should have been hooked.");
+ test.strictEqual(this.obj.add1(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add1", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ this.order = [];
+ test.strictEqual(this.obj.add2(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add2", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ this.order = [];
+ test.strictEqual(this.obj.add3(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["add3", 1, 2, 3], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, all properties': function(test) {
+ test.expect(7);
+ // Pre- & post-hook.
+ var result = hooker.hook(this.obj, {
+ pre: function(a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.that.track("before", this.prop, a, b);
+ },
+ post: function(result, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.that.track("after", this.prop, a, b, result);
+ }
+ });
+ test.deepEqual(result.sort(), ["add1", "add2", "add3"], "all functions should have been hooked.");
+ test.strictEqual(this.obj.add1(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add1", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ this.order = [];
+ test.strictEqual(this.obj.add2(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add2", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ this.order = [];
+ test.strictEqual(this.obj.add3(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, 2, 3, "add3", 1, 2, 3, "after", 1, 2, 3, 6], "functions should execute in-order.");
+ test.done();
+ },
+ 'pre- & post-hook, all properties, passName': function(test) {
+ test.expect(6);
+ // Pre- & post-hook.
+ hooker.hook(this.obj, {
+ passName: true,
+ pre: function(name, a, b) {
+ // Arguments are passed into pre-hook as specified.
+ this.that.track("before", this.prop, name, a, b);
+ },
+ post: function(result, name, a, b) {
+ // Arguments to post-hook are the original function's return value,
+ // followed by the specified function arguments.
+ this.that.track("after", this.prop, name, a, b, result);
+ }
+ });
+ test.strictEqual(this.obj.add1(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, "add1", 2, 3, "add1", 1, 2, 3, "after", 1, "add1", 2, 3, 6], "functions should execute in-order.");
+ this.order = [];
+ test.strictEqual(this.obj.add2(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, "add2", 2, 3, "add2", 1, 2, 3, "after", 1, "add2", 2, 3, 6], "functions should execute in-order.");
+ this.order = [];
+ test.strictEqual(this.obj.add3(2, 3), 6, "should return the original function's result.");
+ test.deepEqual(this.order, ["before", 1, "add3", 2, 3, "add3", 1, 2, 3, "after", 1, "add3", 2, 3, 6], "functions should execute in-order.");
+ test.done();
+ },
+ 'unhook one property': function(test) {
+ test.expect(5);
+ var orig = this.add;
+ hooker.hook(this, "add", function() {});
+ var result = hooker.unhook(this, "add");
+ test.deepEqual(result, ["add"], "one function should have been unhooked.");
+ test.strictEqual(this.add, orig, "should have unhooked, restoring the original function");
+ result = hooker.unhook(this, "add");
+ test.deepEqual(result, [], "nothing should have been unhooked.");
+ test.strictEqual(this.add, orig, "shouldn't explode if already unhooked");
+ test.strictEqual(this.add.orig, undefined, "original function shouldn't have an orig property");
+ test.done();
+ },
+ 'unhook some properties': function(test) {
+ test.expect(6);
+ var add1 = this.obj.add1;
+ var add2 = this.obj.add2;
+ hooker.hook(this.obj, ["add1", "add2"], function() {});
+ test.strictEqual(hooker.orig(this.obj, "add1"), add1, "should return a refernce to the original function");
+ test.strictEqual(hooker.orig(this.obj, "add2"), add2, "should return a refernce to the original function");
+ test.strictEqual(hooker.orig(this.obj, "add3"), undefined, "should not have been hooked, so should not have an original function");
+ var result = hooker.unhook(this.obj, ["add1", "add2"]);
+ test.deepEqual(result.sort(), ["add1", "add2"], "both functions should have been unhooked.");
+ test.strictEqual(this.obj.add1, add1, "should have unhooked, restoring the original function");
+ test.strictEqual(this.obj.add2, add2, "should have unhooked, restoring the original function");
+ test.done();
+ },
+ 'unhook all properties': function(test) {
+ test.expect(7);
+ var add1 = this.obj.add1;
+ var add2 = this.obj.add2;
+ var add3 = this.obj.add3;
+ hooker.hook(this.obj, function() {});
+ test.strictEqual(hooker.orig(this.obj, "add1"), add1, "should return a refernce to the original function");
+ test.strictEqual(hooker.orig(this.obj, "add2"), add2, "should return a refernce to the original function");
+ test.strictEqual(hooker.orig(this.obj, "add3"), add3, "should return a refernce to the original function");
+ var result = hooker.unhook(this.obj);
+ test.deepEqual(result.sort(), ["add1", "add2", "add3"], "all functions should have been unhooked.");
+ test.strictEqual(this.obj.add1, add1, "should have unhooked, restoring the original function");
+ test.strictEqual(this.obj.add2, add2, "should have unhooked, restoring the original function");
+ test.strictEqual(this.obj.add3, add3, "should have unhooked, restoring the original function");
+ test.done();
+ }
+};