aboutsummaryrefslogtreecommitdiff
path: root/node_modules/mocha/lib
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2016-10-10 03:43:44 +0200
committerFlorian Dold <florian.dold@gmail.com>2016-10-10 03:43:44 +0200
commitabd94a7f5a50f43c797a11b53549ae48fff667c3 (patch)
treeab8ed457f65cdd72e13e0571d2975729428f1551 /node_modules/mocha/lib
parenta0247c6a3fd6a09a41a7e35a3441324c4dcb58be (diff)
downloadwallet-core-abd94a7f5a50f43c797a11b53549ae48fff667c3.tar.xz
add node_modules to address #4364
Diffstat (limited to 'node_modules/mocha/lib')
-rw-r--r--node_modules/mocha/lib/browser/debug.js4
-rw-r--r--node_modules/mocha/lib/browser/events.js193
-rw-r--r--node_modules/mocha/lib/browser/progress.js117
-rw-r--r--node_modules/mocha/lib/browser/tty.js11
-rw-r--r--node_modules/mocha/lib/context.js104
-rw-r--r--node_modules/mocha/lib/hook.js46
-rw-r--r--node_modules/mocha/lib/interfaces/bdd.js117
-rw-r--r--node_modules/mocha/lib/interfaces/common.js85
-rw-r--r--node_modules/mocha/lib/interfaces/exports.js61
-rw-r--r--node_modules/mocha/lib/interfaces/index.js4
-rw-r--r--node_modules/mocha/lib/interfaces/qunit.js94
-rw-r--r--node_modules/mocha/lib/interfaces/tdd.js106
-rw-r--r--node_modules/mocha/lib/mocha.js503
-rw-r--r--node_modules/mocha/lib/ms.js128
-rw-r--r--node_modules/mocha/lib/pending.js15
-rw-r--r--node_modules/mocha/lib/reporters/base.js487
-rw-r--r--node_modules/mocha/lib/reporters/doc.js62
-rw-r--r--node_modules/mocha/lib/reporters/dot.js66
-rw-r--r--node_modules/mocha/lib/reporters/html-cov.js56
-rw-r--r--node_modules/mocha/lib/reporters/html.js343
-rw-r--r--node_modules/mocha/lib/reporters/index.js19
-rw-r--r--node_modules/mocha/lib/reporters/json-cov.js151
-rw-r--r--node_modules/mocha/lib/reporters/json-stream.js60
-rw-r--r--node_modules/mocha/lib/reporters/json.js90
-rw-r--r--node_modules/mocha/lib/reporters/landing.js92
-rw-r--r--node_modules/mocha/lib/reporters/list.js61
-rw-r--r--node_modules/mocha/lib/reporters/markdown.js97
-rw-r--r--node_modules/mocha/lib/reporters/min.js36
-rw-r--r--node_modules/mocha/lib/reporters/nyan.js261
-rw-r--r--node_modules/mocha/lib/reporters/progress.js89
-rw-r--r--node_modules/mocha/lib/reporters/spec.js83
-rw-r--r--node_modules/mocha/lib/reporters/tap.js68
-rw-r--r--node_modules/mocha/lib/reporters/templates/coverage.jade51
-rw-r--r--node_modules/mocha/lib/reporters/templates/menu.jade13
-rw-r--r--node_modules/mocha/lib/reporters/templates/script.html34
-rw-r--r--node_modules/mocha/lib/reporters/templates/style.html324
-rw-r--r--node_modules/mocha/lib/reporters/xunit.js166
-rw-r--r--node_modules/mocha/lib/runnable.js363
-rw-r--r--node_modules/mocha/lib/runner.js894
-rw-r--r--node_modules/mocha/lib/suite.js395
-rw-r--r--node_modules/mocha/lib/template.html18
-rw-r--r--node_modules/mocha/lib/test.js44
-rw-r--r--node_modules/mocha/lib/utils.js750
43 files changed, 6761 insertions, 0 deletions
diff --git a/node_modules/mocha/lib/browser/debug.js b/node_modules/mocha/lib/browser/debug.js
new file mode 100644
index 000000000..ba232896d
--- /dev/null
+++ b/node_modules/mocha/lib/browser/debug.js
@@ -0,0 +1,4 @@
+/* eslint-disable no-unused-vars */
+module.exports = function(type) {
+ return function() {};
+};
diff --git a/node_modules/mocha/lib/browser/events.js b/node_modules/mocha/lib/browser/events.js
new file mode 100644
index 000000000..b4342f620
--- /dev/null
+++ b/node_modules/mocha/lib/browser/events.js
@@ -0,0 +1,193 @@
+/**
+ * Module exports.
+ */
+
+exports.EventEmitter = EventEmitter;
+
+/**
+ * Object#toString reference.
+ */
+var objToString = Object.prototype.toString;
+
+/**
+ * Check if a value is an array.
+ *
+ * @api private
+ * @param {*} val The value to test.
+ * @return {boolean} true if the value is an array, otherwise false.
+ */
+function isArray(val) {
+ return objToString.call(val) === '[object Array]';
+}
+
+/**
+ * Event emitter constructor.
+ *
+ * @api public
+ */
+function EventEmitter() {}
+
+/**
+ * Add a listener.
+ *
+ * @api public
+ * @param {string} name Event name.
+ * @param {Function} fn Event handler.
+ * @return {EventEmitter} Emitter instance.
+ */
+EventEmitter.prototype.on = function(name, fn) {
+ if (!this.$events) {
+ this.$events = {};
+ }
+
+ if (!this.$events[name]) {
+ this.$events[name] = fn;
+ } else if (isArray(this.$events[name])) {
+ this.$events[name].push(fn);
+ } else {
+ this.$events[name] = [this.$events[name], fn];
+ }
+
+ return this;
+};
+
+EventEmitter.prototype.addListener = EventEmitter.prototype.on;
+
+/**
+ * Adds a volatile listener.
+ *
+ * @api public
+ * @param {string} name Event name.
+ * @param {Function} fn Event handler.
+ * @return {EventEmitter} Emitter instance.
+ */
+EventEmitter.prototype.once = function(name, fn) {
+ var self = this;
+
+ function on() {
+ self.removeListener(name, on);
+ fn.apply(this, arguments);
+ }
+
+ on.listener = fn;
+ this.on(name, on);
+
+ return this;
+};
+
+/**
+ * Remove a listener.
+ *
+ * @api public
+ * @param {string} name Event name.
+ * @param {Function} fn Event handler.
+ * @return {EventEmitter} Emitter instance.
+ */
+EventEmitter.prototype.removeListener = function(name, fn) {
+ if (this.$events && this.$events[name]) {
+ var list = this.$events[name];
+
+ if (isArray(list)) {
+ var pos = -1;
+
+ for (var i = 0, l = list.length; i < l; i++) {
+ if (list[i] === fn || (list[i].listener && list[i].listener === fn)) {
+ pos = i;
+ break;
+ }
+ }
+
+ if (pos < 0) {
+ return this;
+ }
+
+ list.splice(pos, 1);
+
+ if (!list.length) {
+ delete this.$events[name];
+ }
+ } else if (list === fn || (list.listener && list.listener === fn)) {
+ delete this.$events[name];
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Remove all listeners for an event.
+ *
+ * @api public
+ * @param {string} name Event name.
+ * @return {EventEmitter} Emitter instance.
+ */
+EventEmitter.prototype.removeAllListeners = function(name) {
+ if (name === undefined) {
+ this.$events = {};
+ return this;
+ }
+
+ if (this.$events && this.$events[name]) {
+ this.$events[name] = null;
+ }
+
+ return this;
+};
+
+/**
+ * Get all listeners for a given event.
+ *
+ * @api public
+ * @param {string} name Event name.
+ * @return {EventEmitter} Emitter instance.
+ */
+EventEmitter.prototype.listeners = function(name) {
+ if (!this.$events) {
+ this.$events = {};
+ }
+
+ if (!this.$events[name]) {
+ this.$events[name] = [];
+ }
+
+ if (!isArray(this.$events[name])) {
+ this.$events[name] = [this.$events[name]];
+ }
+
+ return this.$events[name];
+};
+
+/**
+ * Emit an event.
+ *
+ * @api public
+ * @param {string} name Event name.
+ * @return {boolean} true if at least one handler was invoked, else false.
+ */
+EventEmitter.prototype.emit = function(name) {
+ if (!this.$events) {
+ return false;
+ }
+
+ var handler = this.$events[name];
+
+ if (!handler) {
+ return false;
+ }
+
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ if (typeof handler === 'function') {
+ handler.apply(this, args);
+ } else if (isArray(handler)) {
+ var listeners = handler.slice();
+
+ for (var i = 0, l = listeners.length; i < l; i++) {
+ listeners[i].apply(this, args);
+ }
+ } else {
+ return false;
+ }
+
+ return true;
+};
diff --git a/node_modules/mocha/lib/browser/progress.js b/node_modules/mocha/lib/browser/progress.js
new file mode 100644
index 000000000..3186b6ec5
--- /dev/null
+++ b/node_modules/mocha/lib/browser/progress.js
@@ -0,0 +1,117 @@
+/**
+ * Expose `Progress`.
+ */
+
+module.exports = Progress;
+
+/**
+ * Initialize a new `Progress` indicator.
+ */
+function Progress() {
+ this.percent = 0;
+ this.size(0);
+ this.fontSize(11);
+ this.font('helvetica, arial, sans-serif');
+}
+
+/**
+ * Set progress size to `size`.
+ *
+ * @api public
+ * @param {number} size
+ * @return {Progress} Progress instance.
+ */
+Progress.prototype.size = function(size) {
+ this._size = size;
+ return this;
+};
+
+/**
+ * Set text to `text`.
+ *
+ * @api public
+ * @param {string} text
+ * @return {Progress} Progress instance.
+ */
+Progress.prototype.text = function(text) {
+ this._text = text;
+ return this;
+};
+
+/**
+ * Set font size to `size`.
+ *
+ * @api public
+ * @param {number} size
+ * @return {Progress} Progress instance.
+ */
+Progress.prototype.fontSize = function(size) {
+ this._fontSize = size;
+ return this;
+};
+
+/**
+ * Set font to `family`.
+ *
+ * @param {string} family
+ * @return {Progress} Progress instance.
+ */
+Progress.prototype.font = function(family) {
+ this._font = family;
+ return this;
+};
+
+/**
+ * Update percentage to `n`.
+ *
+ * @param {number} n
+ * @return {Progress} Progress instance.
+ */
+Progress.prototype.update = function(n) {
+ this.percent = n;
+ return this;
+};
+
+/**
+ * Draw on `ctx`.
+ *
+ * @param {CanvasRenderingContext2d} ctx
+ * @return {Progress} Progress instance.
+ */
+Progress.prototype.draw = function(ctx) {
+ try {
+ var percent = Math.min(this.percent, 100);
+ var size = this._size;
+ var half = size / 2;
+ var x = half;
+ var y = half;
+ var rad = half - 1;
+ var fontSize = this._fontSize;
+
+ ctx.font = fontSize + 'px ' + this._font;
+
+ var angle = Math.PI * 2 * (percent / 100);
+ ctx.clearRect(0, 0, size, size);
+
+ // outer circle
+ ctx.strokeStyle = '#9f9f9f';
+ ctx.beginPath();
+ ctx.arc(x, y, rad, 0, angle, false);
+ ctx.stroke();
+
+ // inner circle
+ ctx.strokeStyle = '#eee';
+ ctx.beginPath();
+ ctx.arc(x, y, rad - 1, 0, angle, true);
+ ctx.stroke();
+
+ // text
+ var text = this._text || (percent | 0) + '%';
+ var w = ctx.measureText(text).width;
+
+ ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1);
+ } catch (err) {
+ // don't fail if we can't render progress
+ }
+ return this;
+};
diff --git a/node_modules/mocha/lib/browser/tty.js b/node_modules/mocha/lib/browser/tty.js
new file mode 100644
index 000000000..840d6699e
--- /dev/null
+++ b/node_modules/mocha/lib/browser/tty.js
@@ -0,0 +1,11 @@
+exports.isatty = function isatty() {
+ return true;
+};
+
+exports.getWindowSize = function getWindowSize() {
+ if ('innerHeight' in global) {
+ return [global.innerHeight, global.innerWidth];
+ }
+ // In a Web Worker, the DOM Window is not available.
+ return [640, 480];
+};
diff --git a/node_modules/mocha/lib/context.js b/node_modules/mocha/lib/context.js
new file mode 100644
index 000000000..4e7247b84
--- /dev/null
+++ b/node_modules/mocha/lib/context.js
@@ -0,0 +1,104 @@
+/**
+ * Expose `Context`.
+ */
+
+module.exports = Context;
+
+/**
+ * Initialize a new `Context`.
+ *
+ * @api private
+ */
+function Context() {}
+
+/**
+ * Set or get the context `Runnable` to `runnable`.
+ *
+ * @api private
+ * @param {Runnable} runnable
+ * @return {Context}
+ */
+Context.prototype.runnable = function(runnable) {
+ if (!arguments.length) {
+ return this._runnable;
+ }
+ this.test = this._runnable = runnable;
+ return this;
+};
+
+/**
+ * Set test timeout `ms`.
+ *
+ * @api private
+ * @param {number} ms
+ * @return {Context} self
+ */
+Context.prototype.timeout = function(ms) {
+ if (!arguments.length) {
+ return this.runnable().timeout();
+ }
+ this.runnable().timeout(ms);
+ return this;
+};
+
+/**
+ * Set test timeout `enabled`.
+ *
+ * @api private
+ * @param {boolean} enabled
+ * @return {Context} self
+ */
+Context.prototype.enableTimeouts = function(enabled) {
+ this.runnable().enableTimeouts(enabled);
+ return this;
+};
+
+/**
+ * Set test slowness threshold `ms`.
+ *
+ * @api private
+ * @param {number} ms
+ * @return {Context} self
+ */
+Context.prototype.slow = function(ms) {
+ this.runnable().slow(ms);
+ return this;
+};
+
+/**
+ * Mark a test as skipped.
+ *
+ * @api private
+ * @return {Context} self
+ */
+Context.prototype.skip = function() {
+ this.runnable().skip();
+ return this;
+};
+
+/**
+ * Allow a number of retries on failed tests
+ *
+ * @api private
+ * @param {number} n
+ * @return {Context} self
+ */
+Context.prototype.retries = function(n) {
+ if (!arguments.length) {
+ return this.runnable().retries();
+ }
+ this.runnable().retries(n);
+ return this;
+};
+
+/**
+ * Inspect the context void of `._runnable`.
+ *
+ * @api private
+ * @return {string}
+ */
+Context.prototype.inspect = function() {
+ return JSON.stringify(this, function(key, val) {
+ return key === 'runnable' || key === 'test' ? undefined : val;
+ }, 2);
+};
diff --git a/node_modules/mocha/lib/hook.js b/node_modules/mocha/lib/hook.js
new file mode 100644
index 000000000..0417e013c
--- /dev/null
+++ b/node_modules/mocha/lib/hook.js
@@ -0,0 +1,46 @@
+/**
+ * Module dependencies.
+ */
+
+var Runnable = require('./runnable');
+var inherits = require('./utils').inherits;
+
+/**
+ * Expose `Hook`.
+ */
+
+module.exports = Hook;
+
+/**
+ * Initialize a new `Hook` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ */
+function Hook(title, fn) {
+ Runnable.call(this, title, fn);
+ this.type = 'hook';
+}
+
+/**
+ * Inherit from `Runnable.prototype`.
+ */
+inherits(Hook, Runnable);
+
+/**
+ * Get or set the test `err`.
+ *
+ * @param {Error} err
+ * @return {Error}
+ * @api public
+ */
+Hook.prototype.error = function(err) {
+ if (!arguments.length) {
+ err = this._error;
+ this._error = null;
+ return err;
+ }
+
+ this._error = err;
+};
diff --git a/node_modules/mocha/lib/interfaces/bdd.js b/node_modules/mocha/lib/interfaces/bdd.js
new file mode 100644
index 000000000..8519a9a7b
--- /dev/null
+++ b/node_modules/mocha/lib/interfaces/bdd.js
@@ -0,0 +1,117 @@
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite');
+var Test = require('../test');
+var escapeRe = require('escape-string-regexp');
+
+/**
+ * BDD-style interface:
+ *
+ * describe('Array', function() {
+ * describe('#indexOf()', function() {
+ * it('should return -1 when not present', function() {
+ * // ...
+ * });
+ *
+ * it('should return the index when present', function() {
+ * // ...
+ * });
+ * });
+ * });
+ *
+ * @param {Suite} suite Root suite.
+ */
+module.exports = function(suite) {
+ var suites = [suite];
+
+ suite.on('pre-require', function(context, file, mocha) {
+ var common = require('./common')(suites, context);
+
+ context.before = common.before;
+ context.after = common.after;
+ context.beforeEach = common.beforeEach;
+ context.afterEach = common.afterEach;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
+ /**
+ * Describe a "suite" with the given `title`
+ * and callback `fn` containing nested suites
+ * and/or tests.
+ */
+
+ context.describe = context.context = function(title, fn) {
+ var suite = Suite.create(suites[0], title);
+ suite.file = file;
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ return suite;
+ };
+
+ /**
+ * Pending describe.
+ */
+
+ context.xdescribe = context.xcontext = context.describe.skip = function(title, fn) {
+ var suite = Suite.create(suites[0], title);
+ suite.pending = true;
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ };
+
+ /**
+ * Exclusive suite.
+ */
+
+ context.describe.only = function(title, fn) {
+ var suite = context.describe(title, fn);
+ mocha.grep(suite.fullTitle());
+ return suite;
+ };
+
+ /**
+ * Describe a specification or test-case
+ * with the given `title` and callback `fn`
+ * acting as a thunk.
+ */
+
+ var it = context.it = context.specify = function(title, fn) {
+ var suite = suites[0];
+ if (suite.isPending()) {
+ fn = null;
+ }
+ var test = new Test(title, fn);
+ test.file = file;
+ suite.addTest(test);
+ return test;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.it.only = function(title, fn) {
+ var test = it(title, fn);
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
+ mocha.grep(new RegExp(reString));
+ return test;
+ };
+
+ /**
+ * Pending test case.
+ */
+
+ context.xit = context.xspecify = context.it.skip = function(title) {
+ context.it(title);
+ };
+
+ /**
+ * Number of attempts to retry.
+ */
+ context.it.retries = function(n) {
+ context.retries(n);
+ };
+ });
+};
diff --git a/node_modules/mocha/lib/interfaces/common.js b/node_modules/mocha/lib/interfaces/common.js
new file mode 100644
index 000000000..db939085c
--- /dev/null
+++ b/node_modules/mocha/lib/interfaces/common.js
@@ -0,0 +1,85 @@
+'use strict';
+
+/**
+ * Functions common to more than one interface.
+ *
+ * @param {Suite[]} suites
+ * @param {Context} context
+ * @return {Object} An object containing common functions.
+ */
+module.exports = function(suites, context) {
+ return {
+ /**
+ * This is only present if flag --delay is passed into Mocha. It triggers
+ * root suite execution.
+ *
+ * @param {Suite} suite The root wuite.
+ * @return {Function} A function which runs the root suite
+ */
+ runWithSuite: function runWithSuite(suite) {
+ return function run() {
+ suite.run();
+ };
+ },
+
+ /**
+ * Execute before running tests.
+ *
+ * @param {string} name
+ * @param {Function} fn
+ */
+ before: function(name, fn) {
+ suites[0].beforeAll(name, fn);
+ },
+
+ /**
+ * Execute after running tests.
+ *
+ * @param {string} name
+ * @param {Function} fn
+ */
+ after: function(name, fn) {
+ suites[0].afterAll(name, fn);
+ },
+
+ /**
+ * Execute before each test case.
+ *
+ * @param {string} name
+ * @param {Function} fn
+ */
+ beforeEach: function(name, fn) {
+ suites[0].beforeEach(name, fn);
+ },
+
+ /**
+ * Execute after each test case.
+ *
+ * @param {string} name
+ * @param {Function} fn
+ */
+ afterEach: function(name, fn) {
+ suites[0].afterEach(name, fn);
+ },
+
+ test: {
+ /**
+ * Pending test case.
+ *
+ * @param {string} title
+ */
+ skip: function(title) {
+ context.test(title);
+ },
+
+ /**
+ * Number of retry attempts
+ *
+ * @param {number} n
+ */
+ retries: function(n) {
+ context.retries(n);
+ }
+ }
+ };
+};
diff --git a/node_modules/mocha/lib/interfaces/exports.js b/node_modules/mocha/lib/interfaces/exports.js
new file mode 100644
index 000000000..7db6e47c9
--- /dev/null
+++ b/node_modules/mocha/lib/interfaces/exports.js
@@ -0,0 +1,61 @@
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite');
+var Test = require('../test');
+
+/**
+ * Exports-style (as Node.js module) interface:
+ *
+ * exports.Array = {
+ * '#indexOf()': {
+ * 'should return -1 when the value is not present': function() {
+ *
+ * },
+ *
+ * 'should return the correct index when the value is present': function() {
+ *
+ * }
+ * }
+ * };
+ *
+ * @param {Suite} suite Root suite.
+ */
+module.exports = function(suite) {
+ var suites = [suite];
+
+ suite.on('require', visit);
+
+ function visit(obj, file) {
+ var suite;
+ for (var key in obj) {
+ if (typeof obj[key] === 'function') {
+ var fn = obj[key];
+ switch (key) {
+ case 'before':
+ suites[0].beforeAll(fn);
+ break;
+ case 'after':
+ suites[0].afterAll(fn);
+ break;
+ case 'beforeEach':
+ suites[0].beforeEach(fn);
+ break;
+ case 'afterEach':
+ suites[0].afterEach(fn);
+ break;
+ default:
+ var test = new Test(key, fn);
+ test.file = file;
+ suites[0].addTest(test);
+ }
+ } else {
+ suite = Suite.create(suites[0], key);
+ suites.unshift(suite);
+ visit(obj[key], file);
+ suites.shift();
+ }
+ }
+ }
+};
diff --git a/node_modules/mocha/lib/interfaces/index.js b/node_modules/mocha/lib/interfaces/index.js
new file mode 100644
index 000000000..4f825d15b
--- /dev/null
+++ b/node_modules/mocha/lib/interfaces/index.js
@@ -0,0 +1,4 @@
+exports.bdd = require('./bdd');
+exports.tdd = require('./tdd');
+exports.qunit = require('./qunit');
+exports.exports = require('./exports');
diff --git a/node_modules/mocha/lib/interfaces/qunit.js b/node_modules/mocha/lib/interfaces/qunit.js
new file mode 100644
index 000000000..b79dcc68c
--- /dev/null
+++ b/node_modules/mocha/lib/interfaces/qunit.js
@@ -0,0 +1,94 @@
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite');
+var Test = require('../test');
+var escapeRe = require('escape-string-regexp');
+
+/**
+ * QUnit-style interface:
+ *
+ * suite('Array');
+ *
+ * test('#length', function() {
+ * var arr = [1,2,3];
+ * ok(arr.length == 3);
+ * });
+ *
+ * test('#indexOf()', function() {
+ * var arr = [1,2,3];
+ * ok(arr.indexOf(1) == 0);
+ * ok(arr.indexOf(2) == 1);
+ * ok(arr.indexOf(3) == 2);
+ * });
+ *
+ * suite('String');
+ *
+ * test('#length', function() {
+ * ok('foo'.length == 3);
+ * });
+ *
+ * @param {Suite} suite Root suite.
+ */
+module.exports = function(suite) {
+ var suites = [suite];
+
+ suite.on('pre-require', function(context, file, mocha) {
+ var common = require('./common')(suites, context);
+
+ context.before = common.before;
+ context.after = common.after;
+ context.beforeEach = common.beforeEach;
+ context.afterEach = common.afterEach;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
+ /**
+ * Describe a "suite" with the given `title`.
+ */
+
+ context.suite = function(title) {
+ if (suites.length > 1) {
+ suites.shift();
+ }
+ var suite = Suite.create(suites[0], title);
+ suite.file = file;
+ suites.unshift(suite);
+ return suite;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.suite.only = function(title, fn) {
+ var suite = context.suite(title, fn);
+ mocha.grep(suite.fullTitle());
+ };
+
+ /**
+ * Describe a specification or test-case
+ * with the given `title` and callback `fn`
+ * acting as a thunk.
+ */
+
+ context.test = function(title, fn) {
+ var test = new Test(title, fn);
+ test.file = file;
+ suites[0].addTest(test);
+ return test;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.test.only = function(title, fn) {
+ var test = context.test(title, fn);
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
+ mocha.grep(new RegExp(reString));
+ };
+
+ context.test.skip = common.test.skip;
+ context.test.retries = common.test.retries;
+ });
+};
diff --git a/node_modules/mocha/lib/interfaces/tdd.js b/node_modules/mocha/lib/interfaces/tdd.js
new file mode 100644
index 000000000..d37936ae4
--- /dev/null
+++ b/node_modules/mocha/lib/interfaces/tdd.js
@@ -0,0 +1,106 @@
+/**
+ * Module dependencies.
+ */
+
+var Suite = require('../suite');
+var Test = require('../test');
+var escapeRe = require('escape-string-regexp');
+
+/**
+ * TDD-style interface:
+ *
+ * suite('Array', function() {
+ * suite('#indexOf()', function() {
+ * suiteSetup(function() {
+ *
+ * });
+ *
+ * test('should return -1 when not present', function() {
+ *
+ * });
+ *
+ * test('should return the index when present', function() {
+ *
+ * });
+ *
+ * suiteTeardown(function() {
+ *
+ * });
+ * });
+ * });
+ *
+ * @param {Suite} suite Root suite.
+ */
+module.exports = function(suite) {
+ var suites = [suite];
+
+ suite.on('pre-require', function(context, file, mocha) {
+ var common = require('./common')(suites, context);
+
+ context.setup = common.beforeEach;
+ context.teardown = common.afterEach;
+ context.suiteSetup = common.before;
+ context.suiteTeardown = common.after;
+ context.run = mocha.options.delay && common.runWithSuite(suite);
+
+ /**
+ * Describe a "suite" with the given `title` and callback `fn` containing
+ * nested suites and/or tests.
+ */
+ context.suite = function(title, fn) {
+ var suite = Suite.create(suites[0], title);
+ suite.file = file;
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ return suite;
+ };
+
+ /**
+ * Pending suite.
+ */
+ context.suite.skip = function(title, fn) {
+ var suite = Suite.create(suites[0], title);
+ suite.pending = true;
+ suites.unshift(suite);
+ fn.call(suite);
+ suites.shift();
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+ context.suite.only = function(title, fn) {
+ var suite = context.suite(title, fn);
+ mocha.grep(suite.fullTitle());
+ };
+
+ /**
+ * Describe a specification or test-case with the given `title` and
+ * callback `fn` acting as a thunk.
+ */
+ context.test = function(title, fn) {
+ var suite = suites[0];
+ if (suite.isPending()) {
+ fn = null;
+ }
+ var test = new Test(title, fn);
+ test.file = file;
+ suite.addTest(test);
+ return test;
+ };
+
+ /**
+ * Exclusive test-case.
+ */
+
+ context.test.only = function(title, fn) {
+ var test = context.test(title, fn);
+ var reString = '^' + escapeRe(test.fullTitle()) + '$';
+ mocha.grep(new RegExp(reString));
+ };
+
+ context.test.skip = common.test.skip;
+ context.test.retries = common.test.retries;
+ });
+};
diff --git a/node_modules/mocha/lib/mocha.js b/node_modules/mocha/lib/mocha.js
new file mode 100644
index 000000000..46775ab55
--- /dev/null
+++ b/node_modules/mocha/lib/mocha.js
@@ -0,0 +1,503 @@
+/*!
+ * mocha
+ * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var escapeRe = require('escape-string-regexp');
+var path = require('path');
+var reporters = require('./reporters');
+var utils = require('./utils');
+
+/**
+ * Expose `Mocha`.
+ */
+
+exports = module.exports = Mocha;
+
+/**
+ * To require local UIs and reporters when running in node.
+ */
+
+if (!process.browser) {
+ var cwd = process.cwd();
+ module.paths.push(cwd, path.join(cwd, 'node_modules'));
+}
+
+/**
+ * Expose internals.
+ */
+
+exports.utils = utils;
+exports.interfaces = require('./interfaces');
+exports.reporters = reporters;
+exports.Runnable = require('./runnable');
+exports.Context = require('./context');
+exports.Runner = require('./runner');
+exports.Suite = require('./suite');
+exports.Hook = require('./hook');
+exports.Test = require('./test');
+
+/**
+ * Return image `name` path.
+ *
+ * @api private
+ * @param {string} name
+ * @return {string}
+ */
+function image(name) {
+ return path.join(__dirname, '../images', name + '.png');
+}
+
+/**
+ * Set up mocha with `options`.
+ *
+ * Options:
+ *
+ * - `ui` name "bdd", "tdd", "exports" etc
+ * - `reporter` reporter instance, defaults to `mocha.reporters.spec`
+ * - `globals` array of accepted globals
+ * - `timeout` timeout in milliseconds
+ * - `retries` number of times to retry failed tests
+ * - `bail` bail on the first test failure
+ * - `slow` milliseconds to wait before considering a test slow
+ * - `ignoreLeaks` ignore global leaks
+ * - `fullTrace` display the full stack-trace on failing
+ * - `grep` string or regexp to filter tests with
+ *
+ * @param {Object} options
+ * @api public
+ */
+function Mocha(options) {
+ options = options || {};
+ this.files = [];
+ this.options = options;
+ if (options.grep) {
+ this.grep(new RegExp(options.grep));
+ }
+ if (options.fgrep) {
+ this.grep(options.fgrep);
+ }
+ this.suite = new exports.Suite('', new exports.Context());
+ this.ui(options.ui);
+ this.bail(options.bail);
+ this.reporter(options.reporter, options.reporterOptions);
+ if (typeof options.timeout !== 'undefined' && options.timeout !== null) {
+ this.timeout(options.timeout);
+ }
+ if (typeof options.retries !== 'undefined' && options.retries !== null) {
+ this.retries(options.retries);
+ }
+ this.useColors(options.useColors);
+ if (options.enableTimeouts !== null) {
+ this.enableTimeouts(options.enableTimeouts);
+ }
+ if (options.slow) {
+ this.slow(options.slow);
+ }
+}
+
+/**
+ * Enable or disable bailing on the first failure.
+ *
+ * @api public
+ * @param {boolean} [bail]
+ */
+Mocha.prototype.bail = function(bail) {
+ if (!arguments.length) {
+ bail = true;
+ }
+ this.suite.bail(bail);
+ return this;
+};
+
+/**
+ * Add test `file`.
+ *
+ * @api public
+ * @param {string} file
+ */
+Mocha.prototype.addFile = function(file) {
+ this.files.push(file);
+ return this;
+};
+
+/**
+ * Set reporter to `reporter`, defaults to "spec".
+ *
+ * @param {String|Function} reporter name or constructor
+ * @param {Object} reporterOptions optional options
+ * @api public
+ * @param {string|Function} reporter name or constructor
+ * @param {Object} reporterOptions optional options
+ */
+Mocha.prototype.reporter = function(reporter, reporterOptions) {
+ if (typeof reporter === 'function') {
+ this._reporter = reporter;
+ } else {
+ reporter = reporter || 'spec';
+ var _reporter;
+ // Try to load a built-in reporter.
+ if (reporters[reporter]) {
+ _reporter = reporters[reporter];
+ }
+ // Try to load reporters from process.cwd() and node_modules
+ if (!_reporter) {
+ try {
+ _reporter = require(reporter);
+ } catch (err) {
+ err.message.indexOf('Cannot find module') !== -1
+ ? console.warn('"' + reporter + '" reporter not found')
+ : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack);
+ }
+ }
+ if (!_reporter && reporter === 'teamcity') {
+ console.warn('The Teamcity reporter was moved to a package named '
+ + 'mocha-teamcity-reporter '
+ + '(https://npmjs.org/package/mocha-teamcity-reporter).');
+ }
+ if (!_reporter) {
+ throw new Error('invalid reporter "' + reporter + '"');
+ }
+ this._reporter = _reporter;
+ }
+ this.options.reporterOptions = reporterOptions;
+ return this;
+};
+
+/**
+ * Set test UI `name`, defaults to "bdd".
+ *
+ * @api public
+ * @param {string} bdd
+ */
+Mocha.prototype.ui = function(name) {
+ name = name || 'bdd';
+ this._ui = exports.interfaces[name];
+ if (!this._ui) {
+ try {
+ this._ui = require(name);
+ } catch (err) {
+ throw new Error('invalid interface "' + name + '"');
+ }
+ }
+ this._ui = this._ui(this.suite);
+
+ this.suite.on('pre-require', function(context) {
+ exports.afterEach = context.afterEach || context.teardown;
+ exports.after = context.after || context.suiteTeardown;
+ exports.beforeEach = context.beforeEach || context.setup;
+ exports.before = context.before || context.suiteSetup;
+ exports.describe = context.describe || context.suite;
+ exports.it = context.it || context.test;
+ exports.setup = context.setup || context.beforeEach;
+ exports.suiteSetup = context.suiteSetup || context.before;
+ exports.suiteTeardown = context.suiteTeardown || context.after;
+ exports.suite = context.suite || context.describe;
+ exports.teardown = context.teardown || context.afterEach;
+ exports.test = context.test || context.it;
+ exports.run = context.run;
+ });
+
+ return this;
+};
+
+/**
+ * Load registered files.
+ *
+ * @api private
+ */
+Mocha.prototype.loadFiles = function(fn) {
+ var self = this;
+ var suite = this.suite;
+ this.files.forEach(function(file) {
+ file = path.resolve(file);
+ suite.emit('pre-require', global, file, self);
+ suite.emit('require', require(file), file, self);
+ suite.emit('post-require', global, file, self);
+ });
+ fn && fn();
+};
+
+/**
+ * Enable growl support.
+ *
+ * @api private
+ */
+Mocha.prototype._growl = function(runner, reporter) {
+ var notify = require('growl');
+
+ runner.on('end', function() {
+ var stats = reporter.stats;
+ if (stats.failures) {
+ var msg = stats.failures + ' of ' + runner.total + ' tests failed';
+ notify(msg, { name: 'mocha', title: 'Failed', image: image('error') });
+ } else {
+ notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', {
+ name: 'mocha',
+ title: 'Passed',
+ image: image('ok')
+ });
+ }
+ });
+};
+
+/**
+ * Add regexp to grep, if `re` is a string it is escaped.
+ *
+ * @param {RegExp|String} re
+ * @return {Mocha}
+ * @api public
+ * @param {RegExp|string} re
+ * @return {Mocha}
+ */
+Mocha.prototype.grep = function(re) {
+ this.options.grep = typeof re === 'string' ? new RegExp(escapeRe(re)) : re;
+ return this;
+};
+
+/**
+ * Invert `.grep()` matches.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.invert = function() {
+ this.options.invert = true;
+ return this;
+};
+
+/**
+ * Ignore global leaks.
+ *
+ * @param {Boolean} ignore
+ * @return {Mocha}
+ * @api public
+ * @param {boolean} ignore
+ * @return {Mocha}
+ */
+Mocha.prototype.ignoreLeaks = function(ignore) {
+ this.options.ignoreLeaks = Boolean(ignore);
+ return this;
+};
+
+/**
+ * Enable global leak checking.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.checkLeaks = function() {
+ this.options.ignoreLeaks = false;
+ return this;
+};
+
+/**
+ * Display long stack-trace on failing
+ *
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.fullTrace = function() {
+ this.options.fullStackTrace = true;
+ return this;
+};
+
+/**
+ * Enable growl support.
+ *
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.growl = function() {
+ this.options.growl = true;
+ return this;
+};
+
+/**
+ * Ignore `globals` array or string.
+ *
+ * @param {Array|String} globals
+ * @return {Mocha}
+ * @api public
+ * @param {Array|string} globals
+ * @return {Mocha}
+ */
+Mocha.prototype.globals = function(globals) {
+ this.options.globals = (this.options.globals || []).concat(globals);
+ return this;
+};
+
+/**
+ * Emit color output.
+ *
+ * @param {Boolean} colors
+ * @return {Mocha}
+ * @api public
+ * @param {boolean} colors
+ * @return {Mocha}
+ */
+Mocha.prototype.useColors = function(colors) {
+ if (colors !== undefined) {
+ this.options.useColors = colors;
+ }
+ return this;
+};
+
+/**
+ * Use inline diffs rather than +/-.
+ *
+ * @param {Boolean} inlineDiffs
+ * @return {Mocha}
+ * @api public
+ * @param {boolean} inlineDiffs
+ * @return {Mocha}
+ */
+Mocha.prototype.useInlineDiffs = function(inlineDiffs) {
+ this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs;
+ return this;
+};
+
+/**
+ * Set the timeout in milliseconds.
+ *
+ * @param {Number} timeout
+ * @return {Mocha}
+ * @api public
+ * @param {number} timeout
+ * @return {Mocha}
+ */
+Mocha.prototype.timeout = function(timeout) {
+ this.suite.timeout(timeout);
+ return this;
+};
+
+/**
+ * Set the number of times to retry failed tests.
+ *
+ * @param {Number} retry times
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.retries = function(n) {
+ this.suite.retries(n);
+ return this;
+};
+
+/**
+ * Set slowness threshold in milliseconds.
+ *
+ * @param {Number} slow
+ * @return {Mocha}
+ * @api public
+ * @param {number} slow
+ * @return {Mocha}
+ */
+Mocha.prototype.slow = function(slow) {
+ this.suite.slow(slow);
+ return this;
+};
+
+/**
+ * Enable timeouts.
+ *
+ * @param {Boolean} enabled
+ * @return {Mocha}
+ * @api public
+ * @param {boolean} enabled
+ * @return {Mocha}
+ */
+Mocha.prototype.enableTimeouts = function(enabled) {
+ this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true);
+ return this;
+};
+
+/**
+ * Makes all tests async (accepting a callback)
+ *
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.asyncOnly = function() {
+ this.options.asyncOnly = true;
+ return this;
+};
+
+/**
+ * Disable syntax highlighting (in browser).
+ *
+ * @api public
+ */
+Mocha.prototype.noHighlighting = function() {
+ this.options.noHighlighting = true;
+ return this;
+};
+
+/**
+ * Enable uncaught errors to propagate (in browser).
+ *
+ * @return {Mocha}
+ * @api public
+ */
+Mocha.prototype.allowUncaught = function() {
+ this.options.allowUncaught = true;
+ return this;
+};
+
+/**
+ * Delay root suite execution.
+ * @returns {Mocha}
+ */
+Mocha.prototype.delay = function delay() {
+ this.options.delay = true;
+ return this;
+};
+
+/**
+ * Run tests and invoke `fn()` when complete.
+ *
+ * @api public
+ * @param {Function} fn
+ * @return {Runner}
+ */
+Mocha.prototype.run = function(fn) {
+ if (this.files.length) {
+ this.loadFiles();
+ }
+ var suite = this.suite;
+ var options = this.options;
+ options.files = this.files;
+ var runner = new exports.Runner(suite, options.delay);
+ var reporter = new this._reporter(runner, options);
+ runner.ignoreLeaks = options.ignoreLeaks !== false;
+ runner.fullStackTrace = options.fullStackTrace;
+ runner.asyncOnly = options.asyncOnly;
+ runner.allowUncaught = options.allowUncaught;
+ if (options.grep) {
+ runner.grep(options.grep, options.invert);
+ }
+ if (options.globals) {
+ runner.globals(options.globals);
+ }
+ if (options.growl) {
+ this._growl(runner, reporter);
+ }
+ if (options.useColors !== undefined) {
+ exports.reporters.Base.useColors = options.useColors;
+ }
+ exports.reporters.Base.inlineDiffs = options.useInlineDiffs;
+
+ function done(failures) {
+ if (reporter.done) {
+ reporter.done(failures, fn);
+ } else {
+ fn && fn(failures);
+ }
+ }
+
+ return runner.run(done);
+};
diff --git a/node_modules/mocha/lib/ms.js b/node_modules/mocha/lib/ms.js
new file mode 100644
index 000000000..12fddc18a
--- /dev/null
+++ b/node_modules/mocha/lib/ms.js
@@ -0,0 +1,128 @@
+/**
+ * Helpers.
+ */
+
+var s = 1000;
+var m = s * 60;
+var h = m * 60;
+var d = h * 24;
+var y = d * 365.25;
+
+/**
+ * Parse or format the given `val`.
+ *
+ * Options:
+ *
+ * - `long` verbose formatting [false]
+ *
+ * @api public
+ * @param {string|number} val
+ * @param {Object} options
+ * @return {string|number}
+ */
+module.exports = function(val, options) {
+ options = options || {};
+ if (typeof val === 'string') {
+ return parse(val);
+ }
+ // https://github.com/mochajs/mocha/pull/1035
+ return options['long'] ? longFormat(val) : shortFormat(val);
+};
+
+/**
+ * Parse the given `str` and return milliseconds.
+ *
+ * @api private
+ * @param {string} str
+ * @return {number}
+ */
+function parse(str) {
+ var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str);
+ if (!match) {
+ return;
+ }
+ var n = parseFloat(match[1]);
+ var type = (match[2] || 'ms').toLowerCase();
+ switch (type) {
+ case 'years':
+ case 'year':
+ case 'y':
+ return n * y;
+ case 'days':
+ case 'day':
+ case 'd':
+ return n * d;
+ case 'hours':
+ case 'hour':
+ case 'h':
+ return n * h;
+ case 'minutes':
+ case 'minute':
+ case 'm':
+ return n * m;
+ case 'seconds':
+ case 'second':
+ case 's':
+ return n * s;
+ case 'ms':
+ return n;
+ default:
+ // No default case
+ }
+}
+
+/**
+ * Short format for `ms`.
+ *
+ * @api private
+ * @param {number} ms
+ * @return {string}
+ */
+function shortFormat(ms) {
+ if (ms >= d) {
+ return Math.round(ms / d) + 'd';
+ }
+ if (ms >= h) {
+ return Math.round(ms / h) + 'h';
+ }
+ if (ms >= m) {
+ return Math.round(ms / m) + 'm';
+ }
+ if (ms >= s) {
+ return Math.round(ms / s) + 's';
+ }
+ return ms + 'ms';
+}
+
+/**
+ * Long format for `ms`.
+ *
+ * @api private
+ * @param {number} ms
+ * @return {string}
+ */
+function longFormat(ms) {
+ return plural(ms, d, 'day')
+ || plural(ms, h, 'hour')
+ || plural(ms, m, 'minute')
+ || plural(ms, s, 'second')
+ || ms + ' ms';
+}
+
+/**
+ * Pluralization helper.
+ *
+ * @api private
+ * @param {number} ms
+ * @param {number} n
+ * @param {string} name
+ */
+function plural(ms, n, name) {
+ if (ms < n) {
+ return;
+ }
+ if (ms < n * 1.5) {
+ return Math.floor(ms / n) + ' ' + name;
+ }
+ return Math.ceil(ms / n) + ' ' + name + 's';
+}
diff --git a/node_modules/mocha/lib/pending.js b/node_modules/mocha/lib/pending.js
new file mode 100644
index 000000000..c847e04e3
--- /dev/null
+++ b/node_modules/mocha/lib/pending.js
@@ -0,0 +1,15 @@
+
+/**
+ * Expose `Pending`.
+ */
+
+module.exports = Pending;
+
+/**
+ * Initialize a new `Pending` error with the given message.
+ *
+ * @param {string} message
+ */
+function Pending(message) {
+ this.message = message;
+}
diff --git a/node_modules/mocha/lib/reporters/base.js b/node_modules/mocha/lib/reporters/base.js
new file mode 100644
index 000000000..5fe0eb71a
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/base.js
@@ -0,0 +1,487 @@
+/**
+ * Module dependencies.
+ */
+
+var tty = require('tty');
+var diff = require('diff');
+var ms = require('../ms');
+var utils = require('../utils');
+var supportsColor = process.browser ? null : require('supports-color');
+
+/**
+ * Expose `Base`.
+ */
+
+exports = module.exports = Base;
+
+/**
+ * Save timer references to avoid Sinon interfering.
+ * See: https://github.com/mochajs/mocha/issues/237
+ */
+
+/* eslint-disable no-unused-vars, no-native-reassign */
+var Date = global.Date;
+var setTimeout = global.setTimeout;
+var setInterval = global.setInterval;
+var clearTimeout = global.clearTimeout;
+var clearInterval = global.clearInterval;
+/* eslint-enable no-unused-vars, no-native-reassign */
+
+/**
+ * Check if both stdio streams are associated with a tty.
+ */
+
+var isatty = tty.isatty(1) && tty.isatty(2);
+
+/**
+ * Enable coloring by default, except in the browser interface.
+ */
+
+exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined));
+
+/**
+ * Inline diffs instead of +/-
+ */
+
+exports.inlineDiffs = false;
+
+/**
+ * Default color map.
+ */
+
+exports.colors = {
+ pass: 90,
+ fail: 31,
+ 'bright pass': 92,
+ 'bright fail': 91,
+ 'bright yellow': 93,
+ pending: 36,
+ suite: 0,
+ 'error title': 0,
+ 'error message': 31,
+ 'error stack': 90,
+ checkmark: 32,
+ fast: 90,
+ medium: 33,
+ slow: 31,
+ green: 32,
+ light: 90,
+ 'diff gutter': 90,
+ 'diff added': 32,
+ 'diff removed': 31
+};
+
+/**
+ * Default symbol map.
+ */
+
+exports.symbols = {
+ ok: '✓',
+ err: '✖',
+ dot: '․'
+};
+
+// With node.js on Windows: use symbols available in terminal default fonts
+if (process.platform === 'win32') {
+ exports.symbols.ok = '\u221A';
+ exports.symbols.err = '\u00D7';
+ exports.symbols.dot = '.';
+}
+
+/**
+ * Color `str` with the given `type`,
+ * allowing colors to be disabled,
+ * as well as user-defined color
+ * schemes.
+ *
+ * @param {string} type
+ * @param {string} str
+ * @return {string}
+ * @api private
+ */
+var color = exports.color = function(type, str) {
+ if (!exports.useColors) {
+ return String(str);
+ }
+ return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Expose term window size, with some defaults for when stderr is not a tty.
+ */
+
+exports.window = {
+ width: 75
+};
+
+if (isatty) {
+ exports.window.width = process.stdout.getWindowSize
+ ? process.stdout.getWindowSize(1)[0]
+ : tty.getWindowSize()[1];
+}
+
+/**
+ * Expose some basic cursor interactions that are common among reporters.
+ */
+
+exports.cursor = {
+ hide: function() {
+ isatty && process.stdout.write('\u001b[?25l');
+ },
+
+ show: function() {
+ isatty && process.stdout.write('\u001b[?25h');
+ },
+
+ deleteLine: function() {
+ isatty && process.stdout.write('\u001b[2K');
+ },
+
+ beginningOfLine: function() {
+ isatty && process.stdout.write('\u001b[0G');
+ },
+
+ CR: function() {
+ if (isatty) {
+ exports.cursor.deleteLine();
+ exports.cursor.beginningOfLine();
+ } else {
+ process.stdout.write('\r');
+ }
+ }
+};
+
+/**
+ * Outut the given `failures` as a list.
+ *
+ * @param {Array} failures
+ * @api public
+ */
+
+exports.list = function(failures) {
+ console.log();
+ failures.forEach(function(test, i) {
+ // format
+ var fmt = color('error title', ' %s) %s:\n')
+ + color('error message', ' %s')
+ + color('error stack', '\n%s\n');
+
+ // msg
+ var msg;
+ var err = test.err;
+ var message;
+ if (err.message && typeof err.message.toString === 'function') {
+ message = err.message + '';
+ } else if (typeof err.inspect === 'function') {
+ message = err.inspect() + '';
+ } else {
+ message = '';
+ }
+ var stack = err.stack || message;
+ var index = stack.indexOf(message);
+ var actual = err.actual;
+ var expected = err.expected;
+ var escape = true;
+
+ if (index === -1) {
+ msg = message;
+ } else {
+ index += message.length;
+ msg = stack.slice(0, index);
+ // remove msg from stack
+ stack = stack.slice(index + 1);
+ }
+
+ // uncaught
+ if (err.uncaught) {
+ msg = 'Uncaught ' + msg;
+ }
+ // explicitly show diff
+ if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) {
+ escape = false;
+ if (!(utils.isString(actual) && utils.isString(expected))) {
+ err.actual = actual = utils.stringify(actual);
+ err.expected = expected = utils.stringify(expected);
+ }
+
+ fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n');
+ var match = message.match(/^([^:]+): expected/);
+ msg = '\n ' + color('error message', match ? match[1] : msg);
+
+ if (exports.inlineDiffs) {
+ msg += inlineDiff(err, escape);
+ } else {
+ msg += unifiedDiff(err, escape);
+ }
+ }
+
+ // indent stack trace
+ stack = stack.replace(/^/gm, ' ');
+
+ console.log(fmt, (i + 1), test.fullTitle(), msg, stack);
+ });
+};
+
+/**
+ * Initialize a new `Base` reporter.
+ *
+ * All other reporters generally
+ * inherit from this reporter, providing
+ * stats such as test duration, number
+ * of tests passed / failed etc.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function Base(runner) {
+ var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 };
+ var failures = this.failures = [];
+
+ if (!runner) {
+ return;
+ }
+ this.runner = runner;
+
+ runner.stats = stats;
+
+ runner.on('start', function() {
+ stats.start = new Date();
+ });
+
+ runner.on('suite', function(suite) {
+ stats.suites = stats.suites || 0;
+ suite.root || stats.suites++;
+ });
+
+ runner.on('test end', function() {
+ stats.tests = stats.tests || 0;
+ stats.tests++;
+ });
+
+ runner.on('pass', function(test) {
+ stats.passes = stats.passes || 0;
+
+ if (test.duration > test.slow()) {
+ test.speed = 'slow';
+ } else if (test.duration > test.slow() / 2) {
+ test.speed = 'medium';
+ } else {
+ test.speed = 'fast';
+ }
+
+ stats.passes++;
+ });
+
+ runner.on('fail', function(test, err) {
+ stats.failures = stats.failures || 0;
+ stats.failures++;
+ test.err = err;
+ failures.push(test);
+ });
+
+ runner.on('end', function() {
+ stats.end = new Date();
+ stats.duration = new Date() - stats.start;
+ });
+
+ runner.on('pending', function() {
+ stats.pending++;
+ });
+}
+
+/**
+ * Output common epilogue used by many of
+ * the bundled reporters.
+ *
+ * @api public
+ */
+Base.prototype.epilogue = function() {
+ var stats = this.stats;
+ var fmt;
+
+ console.log();
+
+ // passes
+ fmt = color('bright pass', ' ')
+ + color('green', ' %d passing')
+ + color('light', ' (%s)');
+
+ console.log(fmt,
+ stats.passes || 0,
+ ms(stats.duration));
+
+ // pending
+ if (stats.pending) {
+ fmt = color('pending', ' ')
+ + color('pending', ' %d pending');
+
+ console.log(fmt, stats.pending);
+ }
+
+ // failures
+ if (stats.failures) {
+ fmt = color('fail', ' %d failing');
+
+ console.log(fmt, stats.failures);
+
+ Base.list(this.failures);
+ console.log();
+ }
+
+ console.log();
+};
+
+/**
+ * Pad the given `str` to `len`.
+ *
+ * @api private
+ * @param {string} str
+ * @param {string} len
+ * @return {string}
+ */
+function pad(str, len) {
+ str = String(str);
+ return Array(len - str.length + 1).join(' ') + str;
+}
+
+/**
+ * Returns an inline diff between 2 strings with coloured ANSI output
+ *
+ * @api private
+ * @param {Error} err with actual/expected
+ * @param {boolean} escape
+ * @return {string} Diff
+ */
+function inlineDiff(err, escape) {
+ var msg = errorDiff(err, 'WordsWithSpace', escape);
+
+ // linenos
+ var lines = msg.split('\n');
+ if (lines.length > 4) {
+ var width = String(lines.length).length;
+ msg = lines.map(function(str, i) {
+ return pad(++i, width) + ' |' + ' ' + str;
+ }).join('\n');
+ }
+
+ // legend
+ msg = '\n'
+ + color('diff removed', 'actual')
+ + ' '
+ + color('diff added', 'expected')
+ + '\n\n'
+ + msg
+ + '\n';
+
+ // indent
+ msg = msg.replace(/^/gm, ' ');
+ return msg;
+}
+
+/**
+ * Returns a unified diff between two strings.
+ *
+ * @api private
+ * @param {Error} err with actual/expected
+ * @param {boolean} escape
+ * @return {string} The diff.
+ */
+function unifiedDiff(err, escape) {
+ var indent = ' ';
+ function cleanUp(line) {
+ if (escape) {
+ line = escapeInvisibles(line);
+ }
+ if (line[0] === '+') {
+ return indent + colorLines('diff added', line);
+ }
+ if (line[0] === '-') {
+ return indent + colorLines('diff removed', line);
+ }
+ if (line.match(/\@\@/)) {
+ return null;
+ }
+ if (line.match(/\\ No newline/)) {
+ return null;
+ }
+ return indent + line;
+ }
+ function notBlank(line) {
+ return typeof line !== 'undefined' && line !== null;
+ }
+ var msg = diff.createPatch('string', err.actual, err.expected);
+ var lines = msg.split('\n').splice(4);
+ return '\n '
+ + colorLines('diff added', '+ expected') + ' '
+ + colorLines('diff removed', '- actual')
+ + '\n\n'
+ + lines.map(cleanUp).filter(notBlank).join('\n');
+}
+
+/**
+ * Return a character diff for `err`.
+ *
+ * @api private
+ * @param {Error} err
+ * @param {string} type
+ * @param {boolean} escape
+ * @return {string}
+ */
+function errorDiff(err, type, escape) {
+ var actual = escape ? escapeInvisibles(err.actual) : err.actual;
+ var expected = escape ? escapeInvisibles(err.expected) : err.expected;
+ return diff['diff' + type](actual, expected).map(function(str) {
+ if (str.added) {
+ return colorLines('diff added', str.value);
+ }
+ if (str.removed) {
+ return colorLines('diff removed', str.value);
+ }
+ return str.value;
+ }).join('');
+}
+
+/**
+ * Returns a string with all invisible characters in plain text
+ *
+ * @api private
+ * @param {string} line
+ * @return {string}
+ */
+function escapeInvisibles(line) {
+ return line.replace(/\t/g, '<tab>')
+ .replace(/\r/g, '<CR>')
+ .replace(/\n/g, '<LF>\n');
+}
+
+/**
+ * Color lines for `str`, using the color `name`.
+ *
+ * @api private
+ * @param {string} name
+ * @param {string} str
+ * @return {string}
+ */
+function colorLines(name, str) {
+ return str.split('\n').map(function(str) {
+ return color(name, str);
+ }).join('\n');
+}
+
+/**
+ * Object#toString reference.
+ */
+var objToString = Object.prototype.toString;
+
+/**
+ * Check that a / b have the same type.
+ *
+ * @api private
+ * @param {Object} a
+ * @param {Object} b
+ * @return {boolean}
+ */
+function sameType(a, b) {
+ return objToString.call(a) === objToString.call(b);
+}
diff --git a/node_modules/mocha/lib/reporters/doc.js b/node_modules/mocha/lib/reporters/doc.js
new file mode 100644
index 000000000..01f3fdc9d
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/doc.js
@@ -0,0 +1,62 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var utils = require('../utils');
+
+/**
+ * Expose `Doc`.
+ */
+
+exports = module.exports = Doc;
+
+/**
+ * Initialize a new `Doc` reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+function Doc(runner) {
+ Base.call(this, runner);
+
+ var indents = 2;
+
+ function indent() {
+ return Array(indents).join(' ');
+ }
+
+ runner.on('suite', function(suite) {
+ if (suite.root) {
+ return;
+ }
+ ++indents;
+ console.log('%s<section class="suite">', indent());
+ ++indents;
+ console.log('%s<h1>%s</h1>', indent(), utils.escape(suite.title));
+ console.log('%s<dl>', indent());
+ });
+
+ runner.on('suite end', function(suite) {
+ if (suite.root) {
+ return;
+ }
+ console.log('%s</dl>', indent());
+ --indents;
+ console.log('%s</section>', indent());
+ --indents;
+ });
+
+ runner.on('pass', function(test) {
+ console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title));
+ var code = utils.escape(utils.clean(test.body));
+ console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code);
+ });
+
+ runner.on('fail', function(test, err) {
+ console.log('%s <dt class="error">%s</dt>', indent(), utils.escape(test.title));
+ var code = utils.escape(utils.clean(test.fn.body));
+ console.log('%s <dd class="error"><pre><code>%s</code></pre></dd>', indent(), code);
+ console.log('%s <dd class="error">%s</dd>', indent(), utils.escape(err));
+ });
+}
diff --git a/node_modules/mocha/lib/reporters/dot.js b/node_modules/mocha/lib/reporters/dot.js
new file mode 100644
index 000000000..e905dc686
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/dot.js
@@ -0,0 +1,66 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+var color = Base.color;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = Dot;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function Dot(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var width = Base.window.width * .75 | 0;
+ var n = -1;
+
+ runner.on('start', function() {
+ process.stdout.write('\n');
+ });
+
+ runner.on('pending', function() {
+ if (++n % width === 0) {
+ process.stdout.write('\n ');
+ }
+ process.stdout.write(color('pending', Base.symbols.dot));
+ });
+
+ runner.on('pass', function(test) {
+ if (++n % width === 0) {
+ process.stdout.write('\n ');
+ }
+ if (test.speed === 'slow') {
+ process.stdout.write(color('bright yellow', Base.symbols.dot));
+ } else {
+ process.stdout.write(color(test.speed, Base.symbols.dot));
+ }
+ });
+
+ runner.on('fail', function() {
+ if (++n % width === 0) {
+ process.stdout.write('\n ');
+ }
+ process.stdout.write(color('fail', Base.symbols.dot));
+ });
+
+ runner.on('end', function() {
+ console.log();
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(Dot, Base);
diff --git a/node_modules/mocha/lib/reporters/html-cov.js b/node_modules/mocha/lib/reporters/html-cov.js
new file mode 100644
index 000000000..e3f2dd91e
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/html-cov.js
@@ -0,0 +1,56 @@
+/**
+ * Module dependencies.
+ */
+
+var JSONCov = require('./json-cov');
+var readFileSync = require('fs').readFileSync;
+var join = require('path').join;
+
+/**
+ * Expose `HTMLCov`.
+ */
+
+exports = module.exports = HTMLCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function HTMLCov(runner) {
+ var jade = require('jade');
+ var file = join(__dirname, '/templates/coverage.jade');
+ var str = readFileSync(file, 'utf8');
+ var fn = jade.compile(str, { filename: file });
+ var self = this;
+
+ JSONCov.call(this, runner, false);
+
+ runner.on('end', function() {
+ process.stdout.write(fn({
+ cov: self.cov,
+ coverageClass: coverageClass
+ }));
+ });
+}
+
+/**
+ * Return coverage class for a given coverage percentage.
+ *
+ * @api private
+ * @param {number} coveragePctg
+ * @return {string}
+ */
+function coverageClass(coveragePctg) {
+ if (coveragePctg >= 75) {
+ return 'high';
+ }
+ if (coveragePctg >= 50) {
+ return 'medium';
+ }
+ if (coveragePctg >= 25) {
+ return 'low';
+ }
+ return 'terrible';
+}
diff --git a/node_modules/mocha/lib/reporters/html.js b/node_modules/mocha/lib/reporters/html.js
new file mode 100644
index 000000000..5167d18bf
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/html.js
@@ -0,0 +1,343 @@
+/* eslint-env browser */
+
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var utils = require('../utils');
+var Progress = require('../browser/progress');
+var escapeRe = require('escape-string-regexp');
+var escape = utils.escape;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+/* eslint-disable no-unused-vars, no-native-reassign */
+var Date = global.Date;
+var setTimeout = global.setTimeout;
+var setInterval = global.setInterval;
+var clearTimeout = global.clearTimeout;
+var clearInterval = global.clearInterval;
+/* eslint-enable no-unused-vars, no-native-reassign */
+
+/**
+ * Expose `HTML`.
+ */
+
+exports = module.exports = HTML;
+
+/**
+ * Stats template.
+ */
+
+var statsTemplate = '<ul id="mocha-stats">'
+ + '<li class="progress"><canvas width="40" height="40"></canvas></li>'
+ + '<li class="passes"><a href="javascript:void(0);">passes:</a> <em>0</em></li>'
+ + '<li class="failures"><a href="javascript:void(0);">failures:</a> <em>0</em></li>'
+ + '<li class="duration">duration: <em>0</em>s</li>'
+ + '</ul>';
+
+/**
+ * Initialize a new `HTML` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function HTML(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var stats = this.stats;
+ var stat = fragment(statsTemplate);
+ var items = stat.getElementsByTagName('li');
+ var passes = items[1].getElementsByTagName('em')[0];
+ var passesLink = items[1].getElementsByTagName('a')[0];
+ var failures = items[2].getElementsByTagName('em')[0];
+ var failuresLink = items[2].getElementsByTagName('a')[0];
+ var duration = items[3].getElementsByTagName('em')[0];
+ var canvas = stat.getElementsByTagName('canvas')[0];
+ var report = fragment('<ul id="mocha-report"></ul>');
+ var stack = [report];
+ var progress;
+ var ctx;
+ var root = document.getElementById('mocha');
+
+ if (canvas.getContext) {
+ var ratio = window.devicePixelRatio || 1;
+ canvas.style.width = canvas.width;
+ canvas.style.height = canvas.height;
+ canvas.width *= ratio;
+ canvas.height *= ratio;
+ ctx = canvas.getContext('2d');
+ ctx.scale(ratio, ratio);
+ progress = new Progress();
+ }
+
+ if (!root) {
+ return error('#mocha div missing, add it to your document');
+ }
+
+ // pass toggle
+ on(passesLink, 'click', function(evt) {
+ evt.preventDefault();
+ unhide();
+ var name = (/pass/).test(report.className) ? '' : ' pass';
+ report.className = report.className.replace(/fail|pass/g, '') + name;
+ if (report.className.trim()) {
+ hideSuitesWithout('test pass');
+ }
+ });
+
+ // failure toggle
+ on(failuresLink, 'click', function(evt) {
+ evt.preventDefault();
+ unhide();
+ var name = (/fail/).test(report.className) ? '' : ' fail';
+ report.className = report.className.replace(/fail|pass/g, '') + name;
+ if (report.className.trim()) {
+ hideSuitesWithout('test fail');
+ }
+ });
+
+ root.appendChild(stat);
+ root.appendChild(report);
+
+ if (progress) {
+ progress.size(40);
+ }
+
+ runner.on('suite', function(suite) {
+ if (suite.root) {
+ return;
+ }
+
+ // suite
+ var url = self.suiteURL(suite);
+ var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title));
+
+ // container
+ stack[0].appendChild(el);
+ stack.unshift(document.createElement('ul'));
+ el.appendChild(stack[0]);
+ });
+
+ runner.on('suite end', function(suite) {
+ if (suite.root) {
+ return;
+ }
+ stack.shift();
+ });
+
+ runner.on('pass', function(test) {
+ var url = self.testURL(test);
+ var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems</span> '
+ + '<a href="%s" class="replay">‣</a></h2></li>';
+ var el = fragment(markup, test.speed, test.title, test.duration, url);
+ self.addCodeToggle(el, test.body);
+ appendToStack(el);
+ updateStats();
+ });
+
+ runner.on('fail', function(test) {
+ var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>',
+ test.title, self.testURL(test));
+ var stackString; // Note: Includes leading newline
+ var message = test.err.toString();
+
+ // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we
+ // check for the result of the stringifying.
+ if (message === '[object Error]') {
+ message = test.err.message;
+ }
+
+ if (test.err.stack) {
+ var indexOfMessage = test.err.stack.indexOf(test.err.message);
+ if (indexOfMessage === -1) {
+ stackString = test.err.stack;
+ } else {
+ stackString = test.err.stack.substr(test.err.message.length + indexOfMessage);
+ }
+ } else if (test.err.sourceURL && test.err.line !== undefined) {
+ // Safari doesn't give you a stack. Let's at least provide a source line.
+ stackString = '\n(' + test.err.sourceURL + ':' + test.err.line + ')';
+ }
+
+ stackString = stackString || '';
+
+ if (test.err.htmlMessage && stackString) {
+ el.appendChild(fragment('<div class="html-error">%s\n<pre class="error">%e</pre></div>',
+ test.err.htmlMessage, stackString));
+ } else if (test.err.htmlMessage) {
+ el.appendChild(fragment('<div class="html-error">%s</div>', test.err.htmlMessage));
+ } else {
+ el.appendChild(fragment('<pre class="error">%e%e</pre>', message, stackString));
+ }
+
+ self.addCodeToggle(el, test.body);
+ appendToStack(el);
+ updateStats();
+ });
+
+ runner.on('pending', function(test) {
+ var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title);
+ appendToStack(el);
+ updateStats();
+ });
+
+ function appendToStack(el) {
+ // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack.
+ if (stack[0]) {
+ stack[0].appendChild(el);
+ }
+ }
+
+ function updateStats() {
+ // TODO: add to stats
+ var percent = stats.tests / this.total * 100 | 0;
+ if (progress) {
+ progress.update(percent).draw(ctx);
+ }
+
+ // update stats
+ var ms = new Date() - stats.start;
+ text(passes, stats.passes);
+ text(failures, stats.failures);
+ text(duration, (ms / 1000).toFixed(2));
+ }
+}
+
+/**
+ * Makes a URL, preserving querystring ("search") parameters.
+ *
+ * @param {string} s
+ * @return {string} A new URL.
+ */
+function makeUrl(s) {
+ var search = window.location.search;
+
+ // Remove previous grep query parameter if present
+ if (search) {
+ search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?');
+ }
+
+ return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeRe(s));
+}
+
+/**
+ * Provide suite URL.
+ *
+ * @param {Object} [suite]
+ */
+HTML.prototype.suiteURL = function(suite) {
+ return makeUrl(suite.fullTitle());
+};
+
+/**
+ * Provide test URL.
+ *
+ * @param {Object} [test]
+ */
+HTML.prototype.testURL = function(test) {
+ return makeUrl(test.fullTitle());
+};
+
+/**
+ * Adds code toggle functionality for the provided test's list element.
+ *
+ * @param {HTMLLIElement} el
+ * @param {string} contents
+ */
+HTML.prototype.addCodeToggle = function(el, contents) {
+ var h2 = el.getElementsByTagName('h2')[0];
+
+ on(h2, 'click', function() {
+ pre.style.display = pre.style.display === 'none' ? 'block' : 'none';
+ });
+
+ var pre = fragment('<pre><code>%e</code></pre>', utils.clean(contents));
+ el.appendChild(pre);
+ pre.style.display = 'none';
+};
+
+/**
+ * Display error `msg`.
+ *
+ * @param {string} msg
+ */
+function error(msg) {
+ document.body.appendChild(fragment('<div id="mocha-error">%s</div>', msg));
+}
+
+/**
+ * Return a DOM fragment from `html`.
+ *
+ * @param {string} html
+ */
+function fragment(html) {
+ var args = arguments;
+ var div = document.createElement('div');
+ var i = 1;
+
+ div.innerHTML = html.replace(/%([se])/g, function(_, type) {
+ switch (type) {
+ case 's': return String(args[i++]);
+ case 'e': return escape(args[i++]);
+ // no default
+ }
+ });
+
+ return div.firstChild;
+}
+
+/**
+ * Check for suites that do not have elements
+ * with `classname`, and hide them.
+ *
+ * @param {text} classname
+ */
+function hideSuitesWithout(classname) {
+ var suites = document.getElementsByClassName('suite');
+ for (var i = 0; i < suites.length; i++) {
+ var els = suites[i].getElementsByClassName(classname);
+ if (!els.length) {
+ suites[i].className += ' hidden';
+ }
+ }
+}
+
+/**
+ * Unhide .hidden suites.
+ */
+function unhide() {
+ var els = document.getElementsByClassName('suite hidden');
+ for (var i = 0; i < els.length; ++i) {
+ els[i].className = els[i].className.replace('suite hidden', 'suite');
+ }
+}
+
+/**
+ * Set an element's text contents.
+ *
+ * @param {HTMLElement} el
+ * @param {string} contents
+ */
+function text(el, contents) {
+ if (el.textContent) {
+ el.textContent = contents;
+ } else {
+ el.innerText = contents;
+ }
+}
+
+/**
+ * Listen on `event` with callback `fn`.
+ */
+function on(el, event, fn) {
+ if (el.addEventListener) {
+ el.addEventListener(event, fn, false);
+ } else {
+ el.attachEvent('on' + event, fn);
+ }
+}
diff --git a/node_modules/mocha/lib/reporters/index.js b/node_modules/mocha/lib/reporters/index.js
new file mode 100644
index 000000000..51f5cffee
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/index.js
@@ -0,0 +1,19 @@
+// Alias exports to a their normalized format Mocha#reporter to prevent a need
+// for dynamic (try/catch) requires, which Browserify doesn't handle.
+exports.Base = exports.base = require('./base');
+exports.Dot = exports.dot = require('./dot');
+exports.Doc = exports.doc = require('./doc');
+exports.TAP = exports.tap = require('./tap');
+exports.JSON = exports.json = require('./json');
+exports.HTML = exports.html = require('./html');
+exports.List = exports.list = require('./list');
+exports.Min = exports.min = require('./min');
+exports.Spec = exports.spec = require('./spec');
+exports.Nyan = exports.nyan = require('./nyan');
+exports.XUnit = exports.xunit = require('./xunit');
+exports.Markdown = exports.markdown = require('./markdown');
+exports.Progress = exports.progress = require('./progress');
+exports.Landing = exports.landing = require('./landing');
+exports.JSONCov = exports['json-cov'] = require('./json-cov');
+exports.HTMLCov = exports['html-cov'] = require('./html-cov');
+exports.JSONStream = exports['json-stream'] = require('./json-stream');
diff --git a/node_modules/mocha/lib/reporters/json-cov.js b/node_modules/mocha/lib/reporters/json-cov.js
new file mode 100644
index 000000000..5a32569f0
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/json-cov.js
@@ -0,0 +1,151 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `JSONCov`.
+ */
+
+exports = module.exports = JSONCov;
+
+/**
+ * Initialize a new `JsCoverage` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ * @param {boolean} output
+ */
+function JSONCov(runner, output) {
+ Base.call(this, runner);
+
+ output = arguments.length === 1 || output;
+ var self = this;
+ var tests = [];
+ var failures = [];
+ var passes = [];
+
+ runner.on('test end', function(test) {
+ tests.push(test);
+ });
+
+ runner.on('pass', function(test) {
+ passes.push(test);
+ });
+
+ runner.on('fail', function(test) {
+ failures.push(test);
+ });
+
+ runner.on('end', function() {
+ var cov = global._$jscoverage || {};
+ var result = self.cov = map(cov);
+ result.stats = self.stats;
+ result.tests = tests.map(clean);
+ result.failures = failures.map(clean);
+ result.passes = passes.map(clean);
+ if (!output) {
+ return;
+ }
+ process.stdout.write(JSON.stringify(result, null, 2));
+ });
+}
+
+/**
+ * Map jscoverage data to a JSON structure
+ * suitable for reporting.
+ *
+ * @api private
+ * @param {Object} cov
+ * @return {Object}
+ */
+
+function map(cov) {
+ var ret = {
+ instrumentation: 'node-jscoverage',
+ sloc: 0,
+ hits: 0,
+ misses: 0,
+ coverage: 0,
+ files: []
+ };
+
+ for (var filename in cov) {
+ if (Object.prototype.hasOwnProperty.call(cov, filename)) {
+ var data = coverage(filename, cov[filename]);
+ ret.files.push(data);
+ ret.hits += data.hits;
+ ret.misses += data.misses;
+ ret.sloc += data.sloc;
+ }
+ }
+
+ ret.files.sort(function(a, b) {
+ return a.filename.localeCompare(b.filename);
+ });
+
+ if (ret.sloc > 0) {
+ ret.coverage = (ret.hits / ret.sloc) * 100;
+ }
+
+ return ret;
+}
+
+/**
+ * Map jscoverage data for a single source file
+ * to a JSON structure suitable for reporting.
+ *
+ * @api private
+ * @param {string} filename name of the source file
+ * @param {Object} data jscoverage coverage data
+ * @return {Object}
+ */
+function coverage(filename, data) {
+ var ret = {
+ filename: filename,
+ coverage: 0,
+ hits: 0,
+ misses: 0,
+ sloc: 0,
+ source: {}
+ };
+
+ data.source.forEach(function(line, num) {
+ num++;
+
+ if (data[num] === 0) {
+ ret.misses++;
+ ret.sloc++;
+ } else if (data[num] !== undefined) {
+ ret.hits++;
+ ret.sloc++;
+ }
+
+ ret.source[num] = {
+ source: line,
+ coverage: data[num] === undefined ? '' : data[num]
+ };
+ });
+
+ ret.coverage = ret.hits / ret.sloc * 100;
+
+ return ret;
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @api private
+ * @param {Object} test
+ * @return {Object}
+ */
+function clean(test) {
+ return {
+ duration: test.duration,
+ currentRetry: test.currentRetry(),
+ fullTitle: test.fullTitle(),
+ title: test.title
+ };
+}
diff --git a/node_modules/mocha/lib/reporters/json-stream.js b/node_modules/mocha/lib/reporters/json-stream.js
new file mode 100644
index 000000000..02399e7db
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/json-stream.js
@@ -0,0 +1,60 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function List(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var total = runner.total;
+
+ runner.on('start', function() {
+ console.log(JSON.stringify(['start', { total: total }]));
+ });
+
+ runner.on('pass', function(test) {
+ console.log(JSON.stringify(['pass', clean(test)]));
+ });
+
+ runner.on('fail', function(test, err) {
+ test = clean(test);
+ test.err = err.message;
+ test.stack = err.stack || null;
+ console.log(JSON.stringify(['fail', test]));
+ });
+
+ runner.on('end', function() {
+ process.stdout.write(JSON.stringify(['end', self.stats]));
+ });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @api private
+ * @param {Object} test
+ * @return {Object}
+ */
+function clean(test) {
+ return {
+ title: test.title,
+ fullTitle: test.fullTitle(),
+ duration: test.duration,
+ currentRetry: test.currentRetry()
+ };
+}
diff --git a/node_modules/mocha/lib/reporters/json.js b/node_modules/mocha/lib/reporters/json.js
new file mode 100644
index 000000000..cd9ec286b
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/json.js
@@ -0,0 +1,90 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `JSON`.
+ */
+
+exports = module.exports = JSONReporter;
+
+/**
+ * Initialize a new `JSON` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function JSONReporter(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var tests = [];
+ var pending = [];
+ var failures = [];
+ var passes = [];
+
+ runner.on('test end', function(test) {
+ tests.push(test);
+ });
+
+ runner.on('pass', function(test) {
+ passes.push(test);
+ });
+
+ runner.on('fail', function(test) {
+ failures.push(test);
+ });
+
+ runner.on('pending', function(test) {
+ pending.push(test);
+ });
+
+ runner.on('end', function() {
+ var obj = {
+ stats: self.stats,
+ tests: tests.map(clean),
+ pending: pending.map(clean),
+ failures: failures.map(clean),
+ passes: passes.map(clean)
+ };
+
+ runner.testResults = obj;
+
+ process.stdout.write(JSON.stringify(obj, null, 2));
+ });
+}
+
+/**
+ * Return a plain-object representation of `test`
+ * free of cyclic properties etc.
+ *
+ * @api private
+ * @param {Object} test
+ * @return {Object}
+ */
+function clean(test) {
+ return {
+ title: test.title,
+ fullTitle: test.fullTitle(),
+ duration: test.duration,
+ currentRetry: test.currentRetry(),
+ err: errorJSON(test.err || {})
+ };
+}
+
+/**
+ * Transform `error` into a JSON object.
+ *
+ * @api private
+ * @param {Error} err
+ * @return {Object}
+ */
+function errorJSON(err) {
+ var res = {};
+ Object.getOwnPropertyNames(err).forEach(function(key) {
+ res[key] = err[key];
+ }, err);
+ return res;
+}
diff --git a/node_modules/mocha/lib/reporters/landing.js b/node_modules/mocha/lib/reporters/landing.js
new file mode 100644
index 000000000..b66b2000c
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/landing.js
@@ -0,0 +1,92 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+var cursor = Base.cursor;
+var color = Base.color;
+
+/**
+ * Expose `Landing`.
+ */
+
+exports = module.exports = Landing;
+
+/**
+ * Airplane color.
+ */
+
+Base.colors.plane = 0;
+
+/**
+ * Airplane crash color.
+ */
+
+Base.colors['plane crash'] = 31;
+
+/**
+ * Runway color.
+ */
+
+Base.colors.runway = 90;
+
+/**
+ * Initialize a new `Landing` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function Landing(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var width = Base.window.width * .75 | 0;
+ var total = runner.total;
+ var stream = process.stdout;
+ var plane = color('plane', '✈');
+ var crashed = -1;
+ var n = 0;
+
+ function runway() {
+ var buf = Array(width).join('-');
+ return ' ' + color('runway', buf);
+ }
+
+ runner.on('start', function() {
+ stream.write('\n\n\n ');
+ cursor.hide();
+ });
+
+ runner.on('test end', function(test) {
+ // check if the plane crashed
+ var col = crashed === -1 ? width * ++n / total | 0 : crashed;
+
+ // show the crash
+ if (test.state === 'failed') {
+ plane = color('plane crash', '✈');
+ crashed = col;
+ }
+
+ // render landing strip
+ stream.write('\u001b[' + (width + 1) + 'D\u001b[2A');
+ stream.write(runway());
+ stream.write('\n ');
+ stream.write(color('runway', Array(col).join('â‹…')));
+ stream.write(plane);
+ stream.write(color('runway', Array(width - col).join('â‹…') + '\n'));
+ stream.write(runway());
+ stream.write('\u001b[0m');
+ });
+
+ runner.on('end', function() {
+ cursor.show();
+ console.log();
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(Landing, Base);
diff --git a/node_modules/mocha/lib/reporters/list.js b/node_modules/mocha/lib/reporters/list.js
new file mode 100644
index 000000000..0e5f910d1
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/list.js
@@ -0,0 +1,61 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+var color = Base.color;
+var cursor = Base.cursor;
+
+/**
+ * Expose `List`.
+ */
+
+exports = module.exports = List;
+
+/**
+ * Initialize a new `List` test reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function List(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var n = 0;
+
+ runner.on('start', function() {
+ console.log();
+ });
+
+ runner.on('test', function(test) {
+ process.stdout.write(color('pass', ' ' + test.fullTitle() + ': '));
+ });
+
+ runner.on('pending', function(test) {
+ var fmt = color('checkmark', ' -')
+ + color('pending', ' %s');
+ console.log(fmt, test.fullTitle());
+ });
+
+ runner.on('pass', function(test) {
+ var fmt = color('checkmark', ' ' + Base.symbols.dot)
+ + color('pass', ' %s: ')
+ + color(test.speed, '%dms');
+ cursor.CR();
+ console.log(fmt, test.fullTitle(), test.duration);
+ });
+
+ runner.on('fail', function(test) {
+ cursor.CR();
+ console.log(color('fail', ' %d) %s'), ++n, test.fullTitle());
+ });
+
+ runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(List, Base);
diff --git a/node_modules/mocha/lib/reporters/markdown.js b/node_modules/mocha/lib/reporters/markdown.js
new file mode 100644
index 000000000..680c55d70
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/markdown.js
@@ -0,0 +1,97 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var utils = require('../utils');
+
+/**
+ * Constants
+ */
+
+var SUITE_PREFIX = '$';
+
+/**
+ * Expose `Markdown`.
+ */
+
+exports = module.exports = Markdown;
+
+/**
+ * Initialize a new `Markdown` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function Markdown(runner) {
+ Base.call(this, runner);
+
+ var level = 0;
+ var buf = '';
+
+ function title(str) {
+ return Array(level).join('#') + ' ' + str;
+ }
+
+ function mapTOC(suite, obj) {
+ var ret = obj;
+ var key = SUITE_PREFIX + suite.title;
+
+ obj = obj[key] = obj[key] || { suite: suite };
+ suite.suites.forEach(function(suite) {
+ mapTOC(suite, obj);
+ });
+
+ return ret;
+ }
+
+ function stringifyTOC(obj, level) {
+ ++level;
+ var buf = '';
+ var link;
+ for (var key in obj) {
+ if (key === 'suite') {
+ continue;
+ }
+ if (key !== SUITE_PREFIX) {
+ link = ' - [' + key.substring(1) + ']';
+ link += '(#' + utils.slug(obj[key].suite.fullTitle()) + ')\n';
+ buf += Array(level).join(' ') + link;
+ }
+ buf += stringifyTOC(obj[key], level);
+ }
+ return buf;
+ }
+
+ function generateTOC(suite) {
+ var obj = mapTOC(suite, {});
+ return stringifyTOC(obj, 0);
+ }
+
+ generateTOC(runner.suite);
+
+ runner.on('suite', function(suite) {
+ ++level;
+ var slug = utils.slug(suite.fullTitle());
+ buf += '<a name="' + slug + '"></a>' + '\n';
+ buf += title(suite.title) + '\n';
+ });
+
+ runner.on('suite end', function() {
+ --level;
+ });
+
+ runner.on('pass', function(test) {
+ var code = utils.clean(test.body);
+ buf += test.title + '.\n';
+ buf += '\n```js\n';
+ buf += code + '\n';
+ buf += '```\n\n';
+ });
+
+ runner.on('end', function() {
+ process.stdout.write('# TOC\n');
+ process.stdout.write(generateTOC(runner.suite));
+ process.stdout.write(buf);
+ });
+}
diff --git a/node_modules/mocha/lib/reporters/min.js b/node_modules/mocha/lib/reporters/min.js
new file mode 100644
index 000000000..2b48212ca
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/min.js
@@ -0,0 +1,36 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+
+/**
+ * Expose `Min`.
+ */
+
+exports = module.exports = Min;
+
+/**
+ * Initialize a new `Min` minimal test reporter (best used with --watch).
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function Min(runner) {
+ Base.call(this, runner);
+
+ runner.on('start', function() {
+ // clear screen
+ process.stdout.write('\u001b[2J');
+ // set cursor position
+ process.stdout.write('\u001b[1;3H');
+ });
+
+ runner.on('end', this.epilogue.bind(this));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(Min, Base);
diff --git a/node_modules/mocha/lib/reporters/nyan.js b/node_modules/mocha/lib/reporters/nyan.js
new file mode 100644
index 000000000..ba1b0509d
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/nyan.js
@@ -0,0 +1,261 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+
+/**
+ * Expose `Dot`.
+ */
+
+exports = module.exports = NyanCat;
+
+/**
+ * Initialize a new `Dot` matrix test reporter.
+ *
+ * @param {Runner} runner
+ * @api public
+ */
+
+function NyanCat(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var width = Base.window.width * .75 | 0;
+ var nyanCatWidth = this.nyanCatWidth = 11;
+
+ this.colorIndex = 0;
+ this.numberOfLines = 4;
+ this.rainbowColors = self.generateColors();
+ this.scoreboardWidth = 5;
+ this.tick = 0;
+ this.trajectories = [[], [], [], []];
+ this.trajectoryWidthMax = (width - nyanCatWidth);
+
+ runner.on('start', function() {
+ Base.cursor.hide();
+ self.draw();
+ });
+
+ runner.on('pending', function() {
+ self.draw();
+ });
+
+ runner.on('pass', function() {
+ self.draw();
+ });
+
+ runner.on('fail', function() {
+ self.draw();
+ });
+
+ runner.on('end', function() {
+ Base.cursor.show();
+ for (var i = 0; i < self.numberOfLines; i++) {
+ write('\n');
+ }
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(NyanCat, Base);
+
+/**
+ * Draw the nyan cat
+ *
+ * @api private
+ */
+
+NyanCat.prototype.draw = function() {
+ this.appendRainbow();
+ this.drawScoreboard();
+ this.drawRainbow();
+ this.drawNyanCat();
+ this.tick = !this.tick;
+};
+
+/**
+ * Draw the "scoreboard" showing the number
+ * of passes, failures and pending tests.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawScoreboard = function() {
+ var stats = this.stats;
+
+ function draw(type, n) {
+ write(' ');
+ write(Base.color(type, n));
+ write('\n');
+ }
+
+ draw('green', stats.passes);
+ draw('fail', stats.failures);
+ draw('pending', stats.pending);
+ write('\n');
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Append the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.appendRainbow = function() {
+ var segment = this.tick ? '_' : '-';
+ var rainbowified = this.rainbowify(segment);
+
+ for (var index = 0; index < this.numberOfLines; index++) {
+ var trajectory = this.trajectories[index];
+ if (trajectory.length >= this.trajectoryWidthMax) {
+ trajectory.shift();
+ }
+ trajectory.push(rainbowified);
+ }
+};
+
+/**
+ * Draw the rainbow.
+ *
+ * @api private
+ */
+
+NyanCat.prototype.drawRainbow = function() {
+ var self = this;
+
+ this.trajectories.forEach(function(line) {
+ write('\u001b[' + self.scoreboardWidth + 'C');
+ write(line.join(''));
+ write('\n');
+ });
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Draw the nyan cat
+ *
+ * @api private
+ */
+NyanCat.prototype.drawNyanCat = function() {
+ var self = this;
+ var startWidth = this.scoreboardWidth + this.trajectories[0].length;
+ var dist = '\u001b[' + startWidth + 'C';
+ var padding = '';
+
+ write(dist);
+ write('_,------,');
+ write('\n');
+
+ write(dist);
+ padding = self.tick ? ' ' : ' ';
+ write('_|' + padding + '/\\_/\\ ');
+ write('\n');
+
+ write(dist);
+ padding = self.tick ? '_' : '__';
+ var tail = self.tick ? '~' : '^';
+ write(tail + '|' + padding + this.face() + ' ');
+ write('\n');
+
+ write(dist);
+ padding = self.tick ? ' ' : ' ';
+ write(padding + '"" "" ');
+ write('\n');
+
+ this.cursorUp(this.numberOfLines);
+};
+
+/**
+ * Draw nyan cat face.
+ *
+ * @api private
+ * @return {string}
+ */
+
+NyanCat.prototype.face = function() {
+ var stats = this.stats;
+ if (stats.failures) {
+ return '( x .x)';
+ } else if (stats.pending) {
+ return '( o .o)';
+ } else if (stats.passes) {
+ return '( ^ .^)';
+ }
+ return '( - .-)';
+};
+
+/**
+ * Move cursor up `n`.
+ *
+ * @api private
+ * @param {number} n
+ */
+
+NyanCat.prototype.cursorUp = function(n) {
+ write('\u001b[' + n + 'A');
+};
+
+/**
+ * Move cursor down `n`.
+ *
+ * @api private
+ * @param {number} n
+ */
+
+NyanCat.prototype.cursorDown = function(n) {
+ write('\u001b[' + n + 'B');
+};
+
+/**
+ * Generate rainbow colors.
+ *
+ * @api private
+ * @return {Array}
+ */
+NyanCat.prototype.generateColors = function() {
+ var colors = [];
+
+ for (var i = 0; i < (6 * 7); i++) {
+ var pi3 = Math.floor(Math.PI / 3);
+ var n = (i * (1.0 / 6));
+ var r = Math.floor(3 * Math.sin(n) + 3);
+ var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3);
+ var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3);
+ colors.push(36 * r + 6 * g + b + 16);
+ }
+
+ return colors;
+};
+
+/**
+ * Apply rainbow to the given `str`.
+ *
+ * @api private
+ * @param {string} str
+ * @return {string}
+ */
+NyanCat.prototype.rainbowify = function(str) {
+ if (!Base.useColors) {
+ return str;
+ }
+ var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length];
+ this.colorIndex += 1;
+ return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m';
+};
+
+/**
+ * Stdout helper.
+ *
+ * @param {string} string A message to write to stdout.
+ */
+function write(string) {
+ process.stdout.write(string);
+}
diff --git a/node_modules/mocha/lib/reporters/progress.js b/node_modules/mocha/lib/reporters/progress.js
new file mode 100644
index 000000000..5349ca893
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/progress.js
@@ -0,0 +1,89 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+var color = Base.color;
+var cursor = Base.cursor;
+
+/**
+ * Expose `Progress`.
+ */
+
+exports = module.exports = Progress;
+
+/**
+ * General progress bar color.
+ */
+
+Base.colors.progress = 90;
+
+/**
+ * Initialize a new `Progress` bar test reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ * @param {Object} options
+ */
+function Progress(runner, options) {
+ Base.call(this, runner);
+
+ var self = this;
+ var width = Base.window.width * .50 | 0;
+ var total = runner.total;
+ var complete = 0;
+ var lastN = -1;
+
+ // default chars
+ options = options || {};
+ options.open = options.open || '[';
+ options.complete = options.complete || 'â–¬';
+ options.incomplete = options.incomplete || Base.symbols.dot;
+ options.close = options.close || ']';
+ options.verbose = false;
+
+ // tests started
+ runner.on('start', function() {
+ console.log();
+ cursor.hide();
+ });
+
+ // tests complete
+ runner.on('test end', function() {
+ complete++;
+
+ var percent = complete / total;
+ var n = width * percent | 0;
+ var i = width - n;
+
+ if (n === lastN && !options.verbose) {
+ // Don't re-render the line if it hasn't changed
+ return;
+ }
+ lastN = n;
+
+ cursor.CR();
+ process.stdout.write('\u001b[J');
+ process.stdout.write(color('progress', ' ' + options.open));
+ process.stdout.write(Array(n).join(options.complete));
+ process.stdout.write(Array(i).join(options.incomplete));
+ process.stdout.write(color('progress', options.close));
+ if (options.verbose) {
+ process.stdout.write(color('progress', ' ' + complete + ' of ' + total));
+ }
+ });
+
+ // tests are complete, output some stats
+ // and the failures if any
+ runner.on('end', function() {
+ cursor.show();
+ console.log();
+ self.epilogue();
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(Progress, Base);
diff --git a/node_modules/mocha/lib/reporters/spec.js b/node_modules/mocha/lib/reporters/spec.js
new file mode 100644
index 000000000..77a73c4f4
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/spec.js
@@ -0,0 +1,83 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var inherits = require('../utils').inherits;
+var color = Base.color;
+var cursor = Base.cursor;
+
+/**
+ * Expose `Spec`.
+ */
+
+exports = module.exports = Spec;
+
+/**
+ * Initialize a new `Spec` test reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function Spec(runner) {
+ Base.call(this, runner);
+
+ var self = this;
+ var indents = 0;
+ var n = 0;
+
+ function indent() {
+ return Array(indents).join(' ');
+ }
+
+ runner.on('start', function() {
+ console.log();
+ });
+
+ runner.on('suite', function(suite) {
+ ++indents;
+ console.log(color('suite', '%s%s'), indent(), suite.title);
+ });
+
+ runner.on('suite end', function() {
+ --indents;
+ if (indents === 1) {
+ console.log();
+ }
+ });
+
+ runner.on('pending', function(test) {
+ var fmt = indent() + color('pending', ' - %s');
+ console.log(fmt, test.title);
+ });
+
+ runner.on('pass', function(test) {
+ var fmt;
+ if (test.speed === 'fast') {
+ fmt = indent()
+ + color('checkmark', ' ' + Base.symbols.ok)
+ + color('pass', ' %s');
+ cursor.CR();
+ console.log(fmt, test.title);
+ } else {
+ fmt = indent()
+ + color('checkmark', ' ' + Base.symbols.ok)
+ + color('pass', ' %s')
+ + color(test.speed, ' (%dms)');
+ cursor.CR();
+ console.log(fmt, test.title, test.duration);
+ }
+ });
+
+ runner.on('fail', function(test) {
+ cursor.CR();
+ console.log(indent() + color('fail', ' %d) %s'), ++n, test.title);
+ });
+
+ runner.on('end', self.epilogue.bind(self));
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(Spec, Base);
diff --git a/node_modules/mocha/lib/reporters/tap.js b/node_modules/mocha/lib/reporters/tap.js
new file mode 100644
index 000000000..d9b1b953a
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/tap.js
@@ -0,0 +1,68 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+
+/**
+ * Expose `TAP`.
+ */
+
+exports = module.exports = TAP;
+
+/**
+ * Initialize a new `TAP` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function TAP(runner) {
+ Base.call(this, runner);
+
+ var n = 1;
+ var passes = 0;
+ var failures = 0;
+
+ runner.on('start', function() {
+ var total = runner.grepTotal(runner.suite);
+ console.log('%d..%d', 1, total);
+ });
+
+ runner.on('test end', function() {
+ ++n;
+ });
+
+ runner.on('pending', function(test) {
+ console.log('ok %d %s # SKIP -', n, title(test));
+ });
+
+ runner.on('pass', function(test) {
+ passes++;
+ console.log('ok %d %s', n, title(test));
+ });
+
+ runner.on('fail', function(test, err) {
+ failures++;
+ console.log('not ok %d %s', n, title(test));
+ if (err.stack) {
+ console.log(err.stack.replace(/^/gm, ' '));
+ }
+ });
+
+ runner.on('end', function() {
+ console.log('# tests ' + (passes + failures));
+ console.log('# pass ' + passes);
+ console.log('# fail ' + failures);
+ });
+}
+
+/**
+ * Return a TAP-safe title of `test`
+ *
+ * @api private
+ * @param {Object} test
+ * @return {String}
+ */
+function title(test) {
+ return test.fullTitle().replace(/#/g, '');
+}
diff --git a/node_modules/mocha/lib/reporters/templates/coverage.jade b/node_modules/mocha/lib/reporters/templates/coverage.jade
new file mode 100644
index 000000000..edd59d886
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/templates/coverage.jade
@@ -0,0 +1,51 @@
+doctype html
+html
+ head
+ title Coverage
+ meta(charset='utf-8')
+ include script.html
+ include style.html
+ body
+ #coverage
+ h1#overview Coverage
+ include menu
+
+ #stats(class=coverageClass(cov.coverage))
+ .percentage #{cov.coverage | 0}%
+ .sloc= cov.sloc
+ .hits= cov.hits
+ .misses= cov.misses
+
+ #files
+ for file in cov.files
+ .file
+ h2(id=file.filename)= file.filename
+ #stats(class=coverageClass(file.coverage))
+ .percentage #{file.coverage | 0}%
+ .sloc= file.sloc
+ .hits= file.hits
+ .misses= file.misses
+
+ table#source
+ thead
+ tr
+ th Line
+ th Hits
+ th Source
+ tbody
+ for line, number in file.source
+ if line.coverage > 0
+ tr.hit
+ td.line= number
+ td.hits= line.coverage
+ td.source= line.source
+ else if 0 === line.coverage
+ tr.miss
+ td.line= number
+ td.hits 0
+ td.source= line.source
+ else
+ tr
+ td.line= number
+ td.hits
+ td.source= line.source || ' '
diff --git a/node_modules/mocha/lib/reporters/templates/menu.jade b/node_modules/mocha/lib/reporters/templates/menu.jade
new file mode 100644
index 000000000..c682e3f0e
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/templates/menu.jade
@@ -0,0 +1,13 @@
+#menu
+ li
+ a(href='#overview') overview
+ for file in cov.files
+ li
+ span.cov(class=coverageClass(file.coverage)) #{file.coverage | 0}
+ a(href='##{file.filename}')
+ segments = file.filename.split('/')
+ basename = segments.pop()
+ if segments.length
+ span.dirname= segments.join('/') + '/'
+ span.basename= basename
+ a#logo(href='http://mochajs.org/') m
diff --git a/node_modules/mocha/lib/reporters/templates/script.html b/node_modules/mocha/lib/reporters/templates/script.html
new file mode 100644
index 000000000..073cf7939
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/templates/script.html
@@ -0,0 +1,34 @@
+<script>
+
+headings = [];
+
+onload = function(){
+ headings = document.querySelectorAll('h2');
+};
+
+onscroll = function(e){
+ var heading = find(window.scrollY);
+ if (!heading) return;
+ var links = document.querySelectorAll('#menu a')
+ , link;
+
+ for (var i = 0, len = links.length; i < len; ++i) {
+ link = links[i];
+ link.className = link.getAttribute('href') == '#' + heading.id
+ ? 'active'
+ : '';
+ }
+};
+
+function find(y) {
+ var i = headings.length
+ , heading;
+
+ while (i--) {
+ heading = headings[i];
+ if (y >= heading.offsetTop) {
+ return heading;
+ }
+ }
+}
+</script>
diff --git a/node_modules/mocha/lib/reporters/templates/style.html b/node_modules/mocha/lib/reporters/templates/style.html
new file mode 100644
index 000000000..4c9c37cfd
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/templates/style.html
@@ -0,0 +1,324 @@
+<style>
+
+body {
+ font: 14px/1.6 "Helvetica Neue", Helvetica, Arial, sans-serif;
+ margin: 0;
+ color: #2C2C2C;
+ border-top: 2px solid #ddd;
+}
+
+#coverage {
+ padding: 60px 400px 60px 60px;
+}
+
+h1 a {
+ color: inherit;
+ font-weight: inherit;
+}
+
+h1 a:hover {
+ text-decoration: none;
+}
+
+.onload h1 {
+ opacity: 1;
+}
+
+h2 {
+ width: 80%;
+ margin-top: 80px;
+ margin-bottom: 0;
+ font-weight: 100;
+ letter-spacing: 1px;
+ border-bottom: 1px solid #eee;
+}
+
+a {
+ color: #8A6343;
+ font-weight: bold;
+ text-decoration: none;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+ul {
+ margin-top: 20px;
+ padding: 0 15px;
+ width: 100%;
+}
+
+ul li {
+ float: left;
+ width: 40%;
+ margin-top: 5px;
+ margin-right: 60px;
+ list-style: none;
+ border-bottom: 1px solid #eee;
+ padding: 5px 0;
+ font-size: 12px;
+}
+
+ul::after {
+ content: '.';
+ height: 0;
+ display: block;
+ visibility: hidden;
+ clear: both;
+}
+
+code {
+ font: 12px monaco, monospace;
+}
+
+pre {
+ margin: 30px;
+ padding: 30px;
+ border: 1px solid #eee;
+ border-bottom-color: #ddd;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ -webkit-box-shadow: inset 0 0 10px #eee;
+ -moz-box-shadow: inset 0 0 10px #eee;
+ box-shadow: inset 0 0 10px #eee;
+ overflow-x: auto;
+}
+
+img {
+ margin: 30px;
+ padding: 1px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ -webkit-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+ -moz-box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+ box-shadow: 0 3px 10px #dedede, 0 1px 5px #888;
+ max-width: 100%;
+}
+
+footer {
+ background: #eee;
+ width: 100%;
+ padding: 50px 0;
+ text-align: right;
+ border-top: 1px solid #ddd;
+}
+
+footer span {
+ display: block;
+ margin-right: 30px;
+ color: #888;
+ font-size: 12px;
+}
+
+#menu {
+ position: fixed;
+ font-size: 12px;
+ overflow-y: auto;
+ top: 0;
+ right: 0;
+ margin: 0;
+ height: 100%;
+ padding: 15px 0;
+ text-align: right;
+ border-left: 1px solid #eee;
+ max-width: 400px;
+ overflow: auto;
+ white-space: nowrap;
+
+ -moz-box-shadow: 0 0 2px #888
+ , inset 5px 0 20px rgba(0,0,0,.5)
+ , inset 5px 0 3px rgba(0,0,0,.3);
+ -webkit-box-shadow: 0 0 2px #888
+ , inset 5px 0 20px rgba(0,0,0,.5)
+ , inset 5px 0 3px rgba(0,0,0,.3);
+ box-shadow: 0 0 2px #888
+ , inset 5px 0 20px rgba(0,0,0,.5)
+ , inset 5px 0 3px rgba(0,0,0,.3);
+ -webkit-font-smoothing: antialiased;
+ background: url("data:image/png;base64,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");
+}
+
+#menu::after {
+ display: block;
+ content: '';
+ padding-top: 80px;
+}
+
+#logo {
+ position: fixed;
+ bottom: 10px;
+ right: 10px;
+ background: rgba(255,255,255,.1);
+ font-size: 11px;
+ display: block;
+ width: 20px;
+ height: 20px;
+ line-height: 20px;
+ text-align: center;
+ -webkit-border-radius: 20px;
+ -moz-border-radius: 20px;
+ border-radius: 20px;
+ -webkit-box-shadow: 0 0 3px rgba(0,0,0,.2);
+ -moz-box-shadow: 0 0 3px rgba(0,0,0,.2);
+ box-shadow: 0 0 3px rgba(0,0,0,.2);
+ color: inherit;
+}
+
+#menu li a {
+ display: block;
+ color: white;
+ padding: 0 35px 0 25px;
+ -webkit-transition: background 300ms;
+ -moz-transition: background 300ms;
+}
+
+#menu li {
+ position: relative;
+ list-style: none;
+}
+
+#menu a:hover,
+#menu a.active {
+ text-decoration: none;
+ background: rgba(255,255,255,.1);
+}
+
+#menu li:hover .cov {
+ opacity: 1;
+}
+
+#menu li .dirname {
+ opacity: .60;
+ padding-right: 2px;
+}
+
+#menu li .basename {
+ opacity: 1;
+}
+
+#menu .cov {
+ background: rgba(0,0,0,.4);
+ position: absolute;
+ top: 0;
+ right: 8px;
+ font-size: 9px;
+ opacity: .6;
+ text-align: left;
+ width: 17px;
+ -webkit-border-radius: 10px;
+ -moz-border-radius: 10px;
+ border-radius: 10px;
+ padding: 2px 3px;
+ text-align: center;
+}
+
+#stats:nth-child(2n) {
+ display: inline-block;
+ margin-top: 15px;
+ border: 1px solid #eee;
+ padding: 10px;
+ -webkit-box-shadow: inset 0 0 2px #eee;
+ -moz-box-shadow: inset 0 0 2px #eee;
+ box-shadow: inset 0 0 2px #eee;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+}
+
+#stats div {
+ float: left;
+ padding: 0 5px;
+}
+
+#stats::after {
+ display: block;
+ content: '';
+ clear: both;
+}
+
+#stats .sloc::after {
+ content: ' SLOC';
+ color: #b6b6b6;
+}
+
+#stats .percentage::after {
+ content: ' coverage';
+ color: #b6b6b6;
+}
+
+#stats .hits,
+#stats .misses {
+ display: none;
+}
+
+.high {
+ color: #00d4b4;
+}
+.medium {
+ color: #e87d0d;
+}
+.low {
+ color: #d4081a;
+}
+.terrible {
+ color: #d4081a;
+ font-weight: bold;
+}
+
+table {
+ width: 80%;
+ margin-top: 10px;
+ border-collapse: collapse;
+ border: 1px solid #cbcbcb;
+ color: #363636;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+}
+
+table thead {
+ display: none;
+}
+
+table td.line,
+table td.hits {
+ width: 20px;
+ background: #eaeaea;
+ text-align: center;
+ font-size: 11px;
+ padding: 0 10px;
+ color: #949494;
+}
+
+table td.hits {
+ width: 10px;
+ padding: 2px 5px;
+ color: rgba(0,0,0,.2);
+ background: #f0f0f0;
+}
+
+tr.miss td.line,
+tr.miss td.hits {
+ background: #e6c3c7;
+}
+
+tr.miss td {
+ background: #f8d5d8;
+}
+
+td.source {
+ padding-left: 15px;
+ line-height: 15px;
+ white-space: pre;
+ font: 12px monaco, monospace;
+}
+
+code .comment { color: #ddd }
+code .init { color: #2F6FAD }
+code .string { color: #5890AD }
+code .keyword { color: #8A6343 }
+code .number { color: #2F6FAD }
+</style>
diff --git a/node_modules/mocha/lib/reporters/xunit.js b/node_modules/mocha/lib/reporters/xunit.js
new file mode 100644
index 000000000..1cfd8f4f5
--- /dev/null
+++ b/node_modules/mocha/lib/reporters/xunit.js
@@ -0,0 +1,166 @@
+/**
+ * Module dependencies.
+ */
+
+var Base = require('./base');
+var utils = require('../utils');
+var inherits = utils.inherits;
+var fs = require('fs');
+var escape = utils.escape;
+var mkdirp = require('mkdirp');
+var path = require('path');
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+/* eslint-disable no-unused-vars, no-native-reassign */
+var Date = global.Date;
+var setTimeout = global.setTimeout;
+var setInterval = global.setInterval;
+var clearTimeout = global.clearTimeout;
+var clearInterval = global.clearInterval;
+/* eslint-enable no-unused-vars, no-native-reassign */
+
+/**
+ * Expose `XUnit`.
+ */
+
+exports = module.exports = XUnit;
+
+/**
+ * Initialize a new `XUnit` reporter.
+ *
+ * @api public
+ * @param {Runner} runner
+ */
+function XUnit(runner, options) {
+ Base.call(this, runner);
+
+ var stats = this.stats;
+ var tests = [];
+ var self = this;
+
+ if (options.reporterOptions && options.reporterOptions.output) {
+ if (!fs.createWriteStream) {
+ throw new Error('file output not supported in browser');
+ }
+ mkdirp.sync(path.dirname(options.reporterOptions.output));
+ self.fileStream = fs.createWriteStream(options.reporterOptions.output);
+ }
+
+ runner.on('pending', function(test) {
+ tests.push(test);
+ });
+
+ runner.on('pass', function(test) {
+ tests.push(test);
+ });
+
+ runner.on('fail', function(test) {
+ tests.push(test);
+ });
+
+ runner.on('end', function() {
+ self.write(tag('testsuite', {
+ name: 'Mocha Tests',
+ tests: stats.tests,
+ failures: stats.failures,
+ errors: stats.failures,
+ skipped: stats.tests - stats.failures - stats.passes,
+ timestamp: (new Date()).toUTCString(),
+ time: (stats.duration / 1000) || 0
+ }, false));
+
+ tests.forEach(function(t) {
+ self.test(t);
+ });
+
+ self.write('</testsuite>');
+ });
+}
+
+/**
+ * Inherit from `Base.prototype`.
+ */
+inherits(XUnit, Base);
+
+/**
+ * Override done to close the stream (if it's a file).
+ *
+ * @param failures
+ * @param {Function} fn
+ */
+XUnit.prototype.done = function(failures, fn) {
+ if (this.fileStream) {
+ this.fileStream.end(function() {
+ fn(failures);
+ });
+ } else {
+ fn(failures);
+ }
+};
+
+/**
+ * Write out the given line.
+ *
+ * @param {string} line
+ */
+XUnit.prototype.write = function(line) {
+ if (this.fileStream) {
+ this.fileStream.write(line + '\n');
+ } else if (typeof process === 'object' && process.stdout) {
+ process.stdout.write(line + '\n');
+ } else {
+ console.log(line);
+ }
+};
+
+/**
+ * Output tag for the given `test.`
+ *
+ * @param {Test} test
+ */
+XUnit.prototype.test = function(test) {
+ var attrs = {
+ classname: test.parent.fullTitle(),
+ name: test.title,
+ time: (test.duration / 1000) || 0
+ };
+
+ if (test.state === 'failed') {
+ var err = test.err;
+ this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack))));
+ } else if (test.isPending()) {
+ this.write(tag('testcase', attrs, false, tag('skipped', {}, true)));
+ } else {
+ this.write(tag('testcase', attrs, true));
+ }
+};
+
+/**
+ * HTML tag helper.
+ *
+ * @param name
+ * @param attrs
+ * @param close
+ * @param content
+ * @return {string}
+ */
+function tag(name, attrs, close, content) {
+ var end = close ? '/>' : '>';
+ var pairs = [];
+ var tag;
+
+ for (var key in attrs) {
+ if (Object.prototype.hasOwnProperty.call(attrs, key)) {
+ pairs.push(key + '="' + escape(attrs[key]) + '"');
+ }
+ }
+
+ tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end;
+ if (content) {
+ tag += content + '</' + name + end;
+ }
+ return tag;
+}
diff --git a/node_modules/mocha/lib/runnable.js b/node_modules/mocha/lib/runnable.js
new file mode 100644
index 000000000..64de4e9a2
--- /dev/null
+++ b/node_modules/mocha/lib/runnable.js
@@ -0,0 +1,363 @@
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var Pending = require('./pending');
+var debug = require('debug')('mocha:runnable');
+var milliseconds = require('./ms');
+var utils = require('./utils');
+var inherits = utils.inherits;
+
+/**
+ * Save timer references to avoid Sinon interfering (see GH-237).
+ */
+
+/* eslint-disable no-unused-vars, no-native-reassign */
+var Date = global.Date;
+var setTimeout = global.setTimeout;
+var setInterval = global.setInterval;
+var clearTimeout = global.clearTimeout;
+var clearInterval = global.clearInterval;
+/* eslint-enable no-unused-vars, no-native-reassign */
+
+/**
+ * Object#toString().
+ */
+
+var toString = Object.prototype.toString;
+
+/**
+ * Expose `Runnable`.
+ */
+
+module.exports = Runnable;
+
+/**
+ * Initialize a new `Runnable` with the given `title` and callback `fn`.
+ *
+ * @param {String} title
+ * @param {Function} fn
+ * @api private
+ * @param {string} title
+ * @param {Function} fn
+ */
+function Runnable(title, fn) {
+ this.title = title;
+ this.fn = fn;
+ this.body = (fn || '').toString();
+ this.async = fn && fn.length;
+ this.sync = !this.async;
+ this._timeout = 2000;
+ this._slow = 75;
+ this._enableTimeouts = true;
+ this.timedOut = false;
+ this._trace = new Error('done() called multiple times');
+ this._retries = -1;
+ this._currentRetry = 0;
+ this.pending = false;
+}
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+inherits(Runnable, EventEmitter);
+
+/**
+ * Set & get timeout `ms`.
+ *
+ * @api private
+ * @param {number|string} ms
+ * @return {Runnable|number} ms or Runnable instance.
+ */
+Runnable.prototype.timeout = function(ms) {
+ if (!arguments.length) {
+ return this._timeout;
+ }
+ if (ms === 0) {
+ this._enableTimeouts = false;
+ }
+ if (typeof ms === 'string') {
+ ms = milliseconds(ms);
+ }
+ debug('timeout %d', ms);
+ this._timeout = ms;
+ if (this.timer) {
+ this.resetTimeout();
+ }
+ return this;
+};
+
+/**
+ * Set & get slow `ms`.
+ *
+ * @api private
+ * @param {number|string} ms
+ * @return {Runnable|number} ms or Runnable instance.
+ */
+Runnable.prototype.slow = function(ms) {
+ if (!arguments.length) {
+ return this._slow;
+ }
+ if (typeof ms === 'string') {
+ ms = milliseconds(ms);
+ }
+ debug('timeout %d', ms);
+ this._slow = ms;
+ return this;
+};
+
+/**
+ * Set and get whether timeout is `enabled`.
+ *
+ * @api private
+ * @param {boolean} enabled
+ * @return {Runnable|boolean} enabled or Runnable instance.
+ */
+Runnable.prototype.enableTimeouts = function(enabled) {
+ if (!arguments.length) {
+ return this._enableTimeouts;
+ }
+ debug('enableTimeouts %s', enabled);
+ this._enableTimeouts = enabled;
+ return this;
+};
+
+/**
+ * Halt and mark as pending.
+ *
+ * @api public
+ */
+Runnable.prototype.skip = function() {
+ throw new Pending();
+};
+
+/**
+ * Check if this runnable or its parent suite is marked as pending.
+ *
+ * @api private
+ */
+Runnable.prototype.isPending = function() {
+ return this.pending || (this.parent && this.parent.isPending());
+};
+
+/**
+ * Set number of retries.
+ *
+ * @api private
+ */
+Runnable.prototype.retries = function(n) {
+ if (!arguments.length) {
+ return this._retries;
+ }
+ this._retries = n;
+};
+
+/**
+ * Get current retry
+ *
+ * @api private
+ */
+Runnable.prototype.currentRetry = function(n) {
+ if (!arguments.length) {
+ return this._currentRetry;
+ }
+ this._currentRetry = n;
+};
+
+/**
+ * Return the full title generated by recursively concatenating the parent's
+ * full title.
+ *
+ * @api public
+ * @return {string}
+ */
+Runnable.prototype.fullTitle = function() {
+ return this.parent.fullTitle() + ' ' + this.title;
+};
+
+/**
+ * Clear the timeout.
+ *
+ * @api private
+ */
+Runnable.prototype.clearTimeout = function() {
+ clearTimeout(this.timer);
+};
+
+/**
+ * Inspect the runnable void of private properties.
+ *
+ * @api private
+ * @return {string}
+ */
+Runnable.prototype.inspect = function() {
+ return JSON.stringify(this, function(key, val) {
+ if (key[0] === '_') {
+ return;
+ }
+ if (key === 'parent') {
+ return '#<Suite>';
+ }
+ if (key === 'ctx') {
+ return '#<Context>';
+ }
+ return val;
+ }, 2);
+};
+
+/**
+ * Reset the timeout.
+ *
+ * @api private
+ */
+Runnable.prototype.resetTimeout = function() {
+ var self = this;
+ var ms = this.timeout() || 1e9;
+
+ if (!this._enableTimeouts) {
+ return;
+ }
+ this.clearTimeout();
+ this.timer = setTimeout(function() {
+ if (!self._enableTimeouts) {
+ return;
+ }
+ self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'));
+ self.timedOut = true;
+ }, ms);
+};
+
+/**
+ * Whitelist a list of globals for this test run.
+ *
+ * @api private
+ * @param {string[]} globals
+ */
+Runnable.prototype.globals = function(globals) {
+ if (!arguments.length) {
+ return this._allowedGlobals;
+ }
+ this._allowedGlobals = globals;
+};
+
+/**
+ * Run the test and invoke `fn(err)`.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+Runnable.prototype.run = function(fn) {
+ var self = this;
+ var start = new Date();
+ var ctx = this.ctx;
+ var finished;
+ var emitted;
+
+ // Sometimes the ctx exists, but it is not runnable
+ if (ctx && ctx.runnable) {
+ ctx.runnable(this);
+ }
+
+ // called multiple times
+ function multiple(err) {
+ if (emitted) {
+ return;
+ }
+ emitted = true;
+ self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate'));
+ }
+
+ // finished
+ function done(err) {
+ var ms = self.timeout();
+ if (self.timedOut) {
+ return;
+ }
+ if (finished) {
+ return multiple(err || self._trace);
+ }
+
+ self.clearTimeout();
+ self.duration = new Date() - start;
+ finished = true;
+ if (!err && self.duration > ms && self._enableTimeouts) {
+ err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.');
+ }
+ fn(err);
+ }
+
+ // for .resetTimeout()
+ this.callback = done;
+
+ // explicit async with `done` argument
+ if (this.async) {
+ this.resetTimeout();
+
+ if (this.allowUncaught) {
+ return callFnAsync(this.fn);
+ }
+ try {
+ callFnAsync(this.fn);
+ } catch (err) {
+ done(utils.getError(err));
+ }
+ return;
+ }
+
+ if (this.allowUncaught) {
+ callFn(this.fn);
+ done();
+ return;
+ }
+
+ // sync or promise-returning
+ try {
+ if (this.isPending()) {
+ done();
+ } else {
+ callFn(this.fn);
+ }
+ } catch (err) {
+ done(utils.getError(err));
+ }
+
+ function callFn(fn) {
+ var result = fn.call(ctx);
+ if (result && typeof result.then === 'function') {
+ self.resetTimeout();
+ result
+ .then(function() {
+ done();
+ // Return null so libraries like bluebird do not warn about
+ // subsequently constructed Promises.
+ return null;
+ },
+ function(reason) {
+ done(reason || new Error('Promise rejected with no or falsy reason'));
+ });
+ } else {
+ if (self.asyncOnly) {
+ return done(new Error('--async-only option in use without declaring `done()` or returning a promise'));
+ }
+
+ done();
+ }
+ }
+
+ function callFnAsync(fn) {
+ fn.call(ctx, function(err) {
+ if (err instanceof Error || toString.call(err) === '[object Error]') {
+ return done(err);
+ }
+ if (err) {
+ if (Object.prototype.toString.call(err) === '[object Object]') {
+ return done(new Error('done() invoked with non-Error: '
+ + JSON.stringify(err)));
+ }
+ return done(new Error('done() invoked with non-Error: ' + err));
+ }
+ done();
+ });
+ }
+};
diff --git a/node_modules/mocha/lib/runner.js b/node_modules/mocha/lib/runner.js
new file mode 100644
index 000000000..ba4d7df97
--- /dev/null
+++ b/node_modules/mocha/lib/runner.js
@@ -0,0 +1,894 @@
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var Pending = require('./pending');
+var utils = require('./utils');
+var inherits = utils.inherits;
+var debug = require('debug')('mocha:runner');
+var Runnable = require('./runnable');
+var filter = utils.filter;
+var indexOf = utils.indexOf;
+var keys = utils.keys;
+var stackFilter = utils.stackTraceFilter();
+var stringify = utils.stringify;
+var type = utils.type;
+var undefinedError = utils.undefinedError;
+var isArray = utils.isArray;
+
+/**
+ * Non-enumerable globals.
+ */
+
+var globals = [
+ 'setTimeout',
+ 'clearTimeout',
+ 'setInterval',
+ 'clearInterval',
+ 'XMLHttpRequest',
+ 'Date',
+ 'setImmediate',
+ 'clearImmediate'
+];
+
+/**
+ * Expose `Runner`.
+ */
+
+module.exports = Runner;
+
+/**
+ * Initialize a `Runner` for the given `suite`.
+ *
+ * Events:
+ *
+ * - `start` execution started
+ * - `end` execution complete
+ * - `suite` (suite) test suite execution started
+ * - `suite end` (suite) all tests (and sub-suites) have finished
+ * - `test` (test) test execution started
+ * - `test end` (test) test completed
+ * - `hook` (hook) hook execution started
+ * - `hook end` (hook) hook complete
+ * - `pass` (test) test passed
+ * - `fail` (test, err) test failed
+ * - `pending` (test) test pending
+ *
+ * @api public
+ * @param {Suite} suite Root suite
+ * @param {boolean} [delay] Whether or not to delay execution of root suite
+ * until ready.
+ */
+function Runner(suite, delay) {
+ var self = this;
+ this._globals = [];
+ this._abort = false;
+ this._delay = delay;
+ this.suite = suite;
+ this.started = false;
+ this.total = suite.total();
+ this.failures = 0;
+ this.on('test end', function(test) {
+ self.checkGlobals(test);
+ });
+ this.on('hook end', function(hook) {
+ self.checkGlobals(hook);
+ });
+ this._defaultGrep = /.*/;
+ this.grep(this._defaultGrep);
+ this.globals(this.globalProps().concat(extraGlobals()));
+}
+
+/**
+ * Wrapper for setImmediate, process.nextTick, or browser polyfill.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+Runner.immediately = global.setImmediate || process.nextTick;
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+inherits(Runner, EventEmitter);
+
+/**
+ * Run tests with full titles matching `re`. Updates runner.total
+ * with number of tests matched.
+ *
+ * @param {RegExp} re
+ * @param {Boolean} invert
+ * @return {Runner} for chaining
+ * @api public
+ * @param {RegExp} re
+ * @param {boolean} invert
+ * @return {Runner} Runner instance.
+ */
+Runner.prototype.grep = function(re, invert) {
+ debug('grep %s', re);
+ this._grep = re;
+ this._invert = invert;
+ this.total = this.grepTotal(this.suite);
+ return this;
+};
+
+/**
+ * Returns the number of tests matching the grep search for the
+ * given suite.
+ *
+ * @param {Suite} suite
+ * @return {Number}
+ * @api public
+ * @param {Suite} suite
+ * @return {number}
+ */
+Runner.prototype.grepTotal = function(suite) {
+ var self = this;
+ var total = 0;
+
+ suite.eachTest(function(test) {
+ var match = self._grep.test(test.fullTitle());
+ if (self._invert) {
+ match = !match;
+ }
+ if (match) {
+ total++;
+ }
+ });
+
+ return total;
+};
+
+/**
+ * Return a list of global properties.
+ *
+ * @return {Array}
+ * @api private
+ */
+Runner.prototype.globalProps = function() {
+ var props = keys(global);
+
+ // non-enumerables
+ for (var i = 0; i < globals.length; ++i) {
+ if (~indexOf(props, globals[i])) {
+ continue;
+ }
+ props.push(globals[i]);
+ }
+
+ return props;
+};
+
+/**
+ * Allow the given `arr` of globals.
+ *
+ * @param {Array} arr
+ * @return {Runner} for chaining
+ * @api public
+ * @param {Array} arr
+ * @return {Runner} Runner instance.
+ */
+Runner.prototype.globals = function(arr) {
+ if (!arguments.length) {
+ return this._globals;
+ }
+ debug('globals %j', arr);
+ this._globals = this._globals.concat(arr);
+ return this;
+};
+
+/**
+ * Check for global variable leaks.
+ *
+ * @api private
+ */
+Runner.prototype.checkGlobals = function(test) {
+ if (this.ignoreLeaks) {
+ return;
+ }
+ var ok = this._globals;
+
+ var globals = this.globalProps();
+ var leaks;
+
+ if (test) {
+ ok = ok.concat(test._allowedGlobals || []);
+ }
+
+ if (this.prevGlobalsLength === globals.length) {
+ return;
+ }
+ this.prevGlobalsLength = globals.length;
+
+ leaks = filterLeaks(ok, globals);
+ this._globals = this._globals.concat(leaks);
+
+ if (leaks.length > 1) {
+ this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + ''));
+ } else if (leaks.length) {
+ this.fail(test, new Error('global leak detected: ' + leaks[0]));
+ }
+};
+
+/**
+ * Fail the given `test`.
+ *
+ * @api private
+ * @param {Test} test
+ * @param {Error} err
+ */
+Runner.prototype.fail = function(test, err) {
+ ++this.failures;
+ test.state = 'failed';
+
+ if (!(err instanceof Error || err && typeof err.message === 'string')) {
+ err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)');
+ }
+
+ err.stack = (this.fullStackTrace || !err.stack)
+ ? err.stack
+ : stackFilter(err.stack);
+
+ this.emit('fail', test, err);
+};
+
+/**
+ * Fail the given `hook` with `err`.
+ *
+ * Hook failures work in the following pattern:
+ * - If bail, then exit
+ * - Failed `before` hook skips all tests in a suite and subsuites,
+ * but jumps to corresponding `after` hook
+ * - Failed `before each` hook skips remaining tests in a
+ * suite and jumps to corresponding `after each` hook,
+ * which is run only once
+ * - Failed `after` hook does not alter
+ * execution order
+ * - Failed `after each` hook skips remaining tests in a
+ * suite and subsuites, but executes other `after each`
+ * hooks
+ *
+ * @api private
+ * @param {Hook} hook
+ * @param {Error} err
+ */
+Runner.prototype.failHook = function(hook, err) {
+ if (hook.ctx && hook.ctx.currentTest) {
+ hook.originalTitle = hook.originalTitle || hook.title;
+ hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"';
+ }
+
+ this.fail(hook, err);
+ if (this.suite.bail()) {
+ this.emit('end');
+ }
+};
+
+/**
+ * Run hook `name` callbacks and then invoke `fn()`.
+ *
+ * @api private
+ * @param {string} name
+ * @param {Function} fn
+ */
+
+Runner.prototype.hook = function(name, fn) {
+ var suite = this.suite;
+ var hooks = suite['_' + name];
+ var self = this;
+
+ function next(i) {
+ var hook = hooks[i];
+ if (!hook) {
+ return fn();
+ }
+ self.currentRunnable = hook;
+
+ hook.ctx.currentTest = self.test;
+
+ self.emit('hook', hook);
+
+ if (!hook.listeners('error').length) {
+ hook.on('error', function(err) {
+ self.failHook(hook, err);
+ });
+ }
+
+ hook.run(function(err) {
+ var testError = hook.error();
+ if (testError) {
+ self.fail(self.test, testError);
+ }
+ if (err) {
+ if (err instanceof Pending) {
+ suite.pending = true;
+ } else {
+ self.failHook(hook, err);
+
+ // stop executing hooks, notify callee of hook err
+ return fn(err);
+ }
+ }
+ self.emit('hook end', hook);
+ delete hook.ctx.currentTest;
+ next(++i);
+ });
+ }
+
+ Runner.immediately(function() {
+ next(0);
+ });
+};
+
+/**
+ * Run hook `name` for the given array of `suites`
+ * in order, and callback `fn(err, errSuite)`.
+ *
+ * @api private
+ * @param {string} name
+ * @param {Array} suites
+ * @param {Function} fn
+ */
+Runner.prototype.hooks = function(name, suites, fn) {
+ var self = this;
+ var orig = this.suite;
+
+ function next(suite) {
+ self.suite = suite;
+
+ if (!suite) {
+ self.suite = orig;
+ return fn();
+ }
+
+ self.hook(name, function(err) {
+ if (err) {
+ var errSuite = self.suite;
+ self.suite = orig;
+ return fn(err, errSuite);
+ }
+
+ next(suites.pop());
+ });
+ }
+
+ next(suites.pop());
+};
+
+/**
+ * Run hooks from the top level down.
+ *
+ * @param {String} name
+ * @param {Function} fn
+ * @api private
+ */
+Runner.prototype.hookUp = function(name, fn) {
+ var suites = [this.suite].concat(this.parents()).reverse();
+ this.hooks(name, suites, fn);
+};
+
+/**
+ * Run hooks from the bottom up.
+ *
+ * @param {String} name
+ * @param {Function} fn
+ * @api private
+ */
+Runner.prototype.hookDown = function(name, fn) {
+ var suites = [this.suite].concat(this.parents());
+ this.hooks(name, suites, fn);
+};
+
+/**
+ * Return an array of parent Suites from
+ * closest to furthest.
+ *
+ * @return {Array}
+ * @api private
+ */
+Runner.prototype.parents = function() {
+ var suite = this.suite;
+ var suites = [];
+ while (suite.parent) {
+ suite = suite.parent;
+ suites.push(suite);
+ }
+ return suites;
+};
+
+/**
+ * Run the current test and callback `fn(err)`.
+ *
+ * @param {Function} fn
+ * @api private
+ */
+Runner.prototype.runTest = function(fn) {
+ var self = this;
+ var test = this.test;
+
+ if (this.asyncOnly) {
+ test.asyncOnly = true;
+ }
+
+ if (this.allowUncaught) {
+ test.allowUncaught = true;
+ return test.run(fn);
+ }
+ try {
+ test.on('error', function(err) {
+ self.fail(test, err);
+ });
+ test.run(fn);
+ } catch (err) {
+ fn(err);
+ }
+};
+
+/**
+ * Run tests in the given `suite` and invoke the callback `fn()` when complete.
+ *
+ * @api private
+ * @param {Suite} suite
+ * @param {Function} fn
+ */
+Runner.prototype.runTests = function(suite, fn) {
+ var self = this;
+ var tests = suite.tests.slice();
+ var test;
+
+ function hookErr(_, errSuite, after) {
+ // before/after Each hook for errSuite failed:
+ var orig = self.suite;
+
+ // for failed 'after each' hook start from errSuite parent,
+ // otherwise start from errSuite itself
+ self.suite = after ? errSuite.parent : errSuite;
+
+ if (self.suite) {
+ // call hookUp afterEach
+ self.hookUp('afterEach', function(err2, errSuite2) {
+ self.suite = orig;
+ // some hooks may fail even now
+ if (err2) {
+ return hookErr(err2, errSuite2, true);
+ }
+ // report error suite
+ fn(errSuite);
+ });
+ } else {
+ // there is no need calling other 'after each' hooks
+ self.suite = orig;
+ fn(errSuite);
+ }
+ }
+
+ function next(err, errSuite) {
+ // if we bail after first err
+ if (self.failures && suite._bail) {
+ return fn();
+ }
+
+ if (self._abort) {
+ return fn();
+ }
+
+ if (err) {
+ return hookErr(err, errSuite, true);
+ }
+
+ // next test
+ test = tests.shift();
+
+ // all done
+ if (!test) {
+ return fn();
+ }
+
+ // grep
+ var match = self._grep.test(test.fullTitle());
+ if (self._invert) {
+ match = !match;
+ }
+ if (!match) {
+ // Run immediately only if we have defined a grep. When we
+ // define a grep — It can cause maximum callstack error if
+ // the grep is doing a large recursive loop by neglecting
+ // all tests. The run immediately function also comes with
+ // a performance cost. So we don't want to run immediately
+ // if we run the whole test suite, because running the whole
+ // test suite don't do any immediate recursive loops. Thus,
+ // allowing a JS runtime to breathe.
+ if (self._grep !== self._defaultGrep) {
+ Runner.immediately(next);
+ } else {
+ next();
+ }
+ return;
+ }
+
+ if (test.isPending()) {
+ self.emit('pending', test);
+ self.emit('test end', test);
+ return next();
+ }
+
+ // execute test and hook(s)
+ self.emit('test', self.test = test);
+ self.hookDown('beforeEach', function(err, errSuite) {
+ if (suite.isPending()) {
+ self.emit('pending', test);
+ self.emit('test end', test);
+ return next();
+ }
+ if (err) {
+ return hookErr(err, errSuite, false);
+ }
+ self.currentRunnable = self.test;
+ self.runTest(function(err) {
+ test = self.test;
+ if (err) {
+ var retry = test.currentRetry();
+ if (err instanceof Pending) {
+ test.pending = true;
+ self.emit('pending', test);
+ } else if (retry < test.retries()) {
+ var clonedTest = test.clone();
+ clonedTest.currentRetry(retry + 1);
+ tests.unshift(clonedTest);
+
+ // Early return + hook trigger so that it doesn't
+ // increment the count wrong
+ return self.hookUp('afterEach', next);
+ } else {
+ self.fail(test, err);
+ }
+ self.emit('test end', test);
+
+ if (err instanceof Pending) {
+ return next();
+ }
+
+ return self.hookUp('afterEach', next);
+ }
+
+ test.state = 'passed';
+ self.emit('pass', test);
+ self.emit('test end', test);
+ self.hookUp('afterEach', next);
+ });
+ });
+ }
+
+ this.next = next;
+ this.hookErr = hookErr;
+ next();
+};
+
+/**
+ * Run the given `suite` and invoke the callback `fn()` when complete.
+ *
+ * @api private
+ * @param {Suite} suite
+ * @param {Function} fn
+ */
+Runner.prototype.runSuite = function(suite, fn) {
+ var i = 0;
+ var self = this;
+ var total = this.grepTotal(suite);
+ var afterAllHookCalled = false;
+
+ debug('run suite %s', suite.fullTitle());
+
+ if (!total || (self.failures && suite._bail)) {
+ return fn();
+ }
+
+ this.emit('suite', this.suite = suite);
+
+ function next(errSuite) {
+ if (errSuite) {
+ // current suite failed on a hook from errSuite
+ if (errSuite === suite) {
+ // if errSuite is current suite
+ // continue to the next sibling suite
+ return done();
+ }
+ // errSuite is among the parents of current suite
+ // stop execution of errSuite and all sub-suites
+ return done(errSuite);
+ }
+
+ if (self._abort) {
+ return done();
+ }
+
+ var curr = suite.suites[i++];
+ if (!curr) {
+ return done();
+ }
+
+ // Avoid grep neglecting large number of tests causing a
+ // huge recursive loop and thus a maximum call stack error.
+ // See comment in `this.runTests()` for more information.
+ if (self._grep !== self._defaultGrep) {
+ Runner.immediately(function() {
+ self.runSuite(curr, next);
+ });
+ } else {
+ self.runSuite(curr, next);
+ }
+ }
+
+ function done(errSuite) {
+ self.suite = suite;
+ self.nextSuite = next;
+
+ if (afterAllHookCalled) {
+ fn(errSuite);
+ } else {
+ // mark that the afterAll block has been called once
+ // and so can be skipped if there is an error in it.
+ afterAllHookCalled = true;
+
+ // remove reference to test
+ delete self.test;
+
+ self.hook('afterAll', function() {
+ self.emit('suite end', suite);
+ fn(errSuite);
+ });
+ }
+ }
+
+ this.nextSuite = next;
+
+ this.hook('beforeAll', function(err) {
+ if (err) {
+ return done();
+ }
+ self.runTests(suite, next);
+ });
+};
+
+/**
+ * Handle uncaught exceptions.
+ *
+ * @param {Error} err
+ * @api private
+ */
+Runner.prototype.uncaught = function(err) {
+ if (err) {
+ debug('uncaught exception %s', err !== function() {
+ return this;
+ }.call(err) ? err : (err.message || err));
+ } else {
+ debug('uncaught undefined exception');
+ err = undefinedError();
+ }
+ err.uncaught = true;
+
+ var runnable = this.currentRunnable;
+
+ if (!runnable) {
+ runnable = new Runnable('Uncaught error outside test suite');
+ runnable.parent = this.suite;
+
+ if (this.started) {
+ this.fail(runnable, err);
+ } else {
+ // Can't recover from this failure
+ this.emit('start');
+ this.fail(runnable, err);
+ this.emit('end');
+ }
+
+ return;
+ }
+
+ runnable.clearTimeout();
+
+ // Ignore errors if complete
+ if (runnable.state) {
+ return;
+ }
+ this.fail(runnable, err);
+
+ // recover from test
+ if (runnable.type === 'test') {
+ this.emit('test end', runnable);
+ this.hookUp('afterEach', this.next);
+ return;
+ }
+
+ // recover from hooks
+ if (runnable.type === 'hook') {
+ var errSuite = this.suite;
+ // if hook failure is in afterEach block
+ if (runnable.fullTitle().indexOf('after each') > -1) {
+ return this.hookErr(err, errSuite, true);
+ }
+ // if hook failure is in beforeEach block
+ if (runnable.fullTitle().indexOf('before each') > -1) {
+ return this.hookErr(err, errSuite, false);
+ }
+ // if hook failure is in after or before blocks
+ return this.nextSuite(errSuite);
+ }
+
+ // bail
+ this.emit('end');
+};
+
+/**
+ * Cleans up the references to all the deferred functions
+ * (before/after/beforeEach/afterEach) and tests of a Suite.
+ * These must be deleted otherwise a memory leak can happen,
+ * as those functions may reference variables from closures,
+ * thus those variables can never be garbage collected as long
+ * as the deferred functions exist.
+ *
+ * @param {Suite} suite
+ */
+function cleanSuiteReferences(suite) {
+ function cleanArrReferences(arr) {
+ for (var i = 0; i < arr.length; i++) {
+ delete arr[i].fn;
+ }
+ }
+
+ if (isArray(suite._beforeAll)) {
+ cleanArrReferences(suite._beforeAll);
+ }
+
+ if (isArray(suite._beforeEach)) {
+ cleanArrReferences(suite._beforeEach);
+ }
+
+ if (isArray(suite._afterAll)) {
+ cleanArrReferences(suite._afterAll);
+ }
+
+ if (isArray(suite._afterEach)) {
+ cleanArrReferences(suite._afterEach);
+ }
+
+ for (var i = 0; i < suite.tests.length; i++) {
+ delete suite.tests[i].fn;
+ }
+}
+
+/**
+ * Run the root suite and invoke `fn(failures)`
+ * on completion.
+ *
+ * @param {Function} fn
+ * @return {Runner} for chaining
+ * @api public
+ * @param {Function} fn
+ * @return {Runner} Runner instance.
+ */
+Runner.prototype.run = function(fn) {
+ var self = this;
+ var rootSuite = this.suite;
+
+ fn = fn || function() {};
+
+ function uncaught(err) {
+ self.uncaught(err);
+ }
+
+ function start() {
+ self.started = true;
+ self.emit('start');
+ self.runSuite(rootSuite, function() {
+ debug('finished running');
+ self.emit('end');
+ });
+ }
+
+ debug('start');
+
+ // references cleanup to avoid memory leaks
+ this.on('suite end', cleanSuiteReferences);
+
+ // callback
+ this.on('end', function() {
+ debug('end');
+ process.removeListener('uncaughtException', uncaught);
+ fn(self.failures);
+ });
+
+ // uncaught exception
+ process.on('uncaughtException', uncaught);
+
+ if (this._delay) {
+ // for reporters, I guess.
+ // might be nice to debounce some dots while we wait.
+ this.emit('waiting', rootSuite);
+ rootSuite.once('run', start);
+ } else {
+ start();
+ }
+
+ return this;
+};
+
+/**
+ * Cleanly abort execution.
+ *
+ * @api public
+ * @return {Runner} Runner instance.
+ */
+Runner.prototype.abort = function() {
+ debug('aborting');
+ this._abort = true;
+
+ return this;
+};
+
+/**
+ * Filter leaks with the given globals flagged as `ok`.
+ *
+ * @api private
+ * @param {Array} ok
+ * @param {Array} globals
+ * @return {Array}
+ */
+function filterLeaks(ok, globals) {
+ return filter(globals, function(key) {
+ // Firefox and Chrome exposes iframes as index inside the window object
+ if (/^d+/.test(key)) {
+ return false;
+ }
+
+ // in firefox
+ // if runner runs in an iframe, this iframe's window.getInterface method not init at first
+ // it is assigned in some seconds
+ if (global.navigator && (/^getInterface/).test(key)) {
+ return false;
+ }
+
+ // an iframe could be approached by window[iframeIndex]
+ // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak
+ if (global.navigator && (/^\d+/).test(key)) {
+ return false;
+ }
+
+ // Opera and IE expose global variables for HTML element IDs (issue #243)
+ if (/^mocha-/.test(key)) {
+ return false;
+ }
+
+ var matched = filter(ok, function(ok) {
+ if (~ok.indexOf('*')) {
+ return key.indexOf(ok.split('*')[0]) === 0;
+ }
+ return key === ok;
+ });
+ return !matched.length && (!global.navigator || key !== 'onerror');
+ });
+}
+
+/**
+ * Array of globals dependent on the environment.
+ *
+ * @return {Array}
+ * @api private
+ */
+function extraGlobals() {
+ if (typeof process === 'object' && typeof process.version === 'string') {
+ var parts = process.version.split('.');
+ var nodeVersion = utils.reduce(parts, function(a, v) {
+ return a << 8 | v;
+ });
+
+ // 'errno' was renamed to process._errno in v0.9.11.
+
+ if (nodeVersion < 0x00090B) {
+ return ['errno'];
+ }
+ }
+
+ return [];
+}
diff --git a/node_modules/mocha/lib/suite.js b/node_modules/mocha/lib/suite.js
new file mode 100644
index 000000000..d43dd4560
--- /dev/null
+++ b/node_modules/mocha/lib/suite.js
@@ -0,0 +1,395 @@
+/**
+ * Module dependencies.
+ */
+
+var EventEmitter = require('events').EventEmitter;
+var Hook = require('./hook');
+var utils = require('./utils');
+var inherits = utils.inherits;
+var debug = require('debug')('mocha:suite');
+var milliseconds = require('./ms');
+
+/**
+ * Expose `Suite`.
+ */
+
+exports = module.exports = Suite;
+
+/**
+ * Create a new `Suite` with the given `title` and parent `Suite`. When a suite
+ * with the same title is already present, that suite is returned to provide
+ * nicer reporter and more flexible meta-testing.
+ *
+ * @api public
+ * @param {Suite} parent
+ * @param {string} title
+ * @return {Suite}
+ */
+exports.create = function(parent, title) {
+ var suite = new Suite(title, parent.ctx);
+ suite.parent = parent;
+ title = suite.fullTitle();
+ parent.addSuite(suite);
+ return suite;
+};
+
+/**
+ * Initialize a new `Suite` with the given `title` and `ctx`.
+ *
+ * @api private
+ * @param {string} title
+ * @param {Context} parentContext
+ */
+function Suite(title, parentContext) {
+ this.title = title;
+ function Context() {}
+ Context.prototype = parentContext;
+ this.ctx = new Context();
+ this.suites = [];
+ this.tests = [];
+ this.pending = false;
+ this._beforeEach = [];
+ this._beforeAll = [];
+ this._afterEach = [];
+ this._afterAll = [];
+ this.root = !title;
+ this._timeout = 2000;
+ this._enableTimeouts = true;
+ this._slow = 75;
+ this._bail = false;
+ this._retries = -1;
+ this.delayed = false;
+}
+
+/**
+ * Inherit from `EventEmitter.prototype`.
+ */
+inherits(Suite, EventEmitter);
+
+/**
+ * Return a clone of this `Suite`.
+ *
+ * @api private
+ * @return {Suite}
+ */
+Suite.prototype.clone = function() {
+ var suite = new Suite(this.title);
+ debug('clone');
+ suite.ctx = this.ctx;
+ suite.timeout(this.timeout());
+ suite.retries(this.retries());
+ suite.enableTimeouts(this.enableTimeouts());
+ suite.slow(this.slow());
+ suite.bail(this.bail());
+ return suite;
+};
+
+/**
+ * Set timeout `ms` or short-hand such as "2s".
+ *
+ * @api private
+ * @param {number|string} ms
+ * @return {Suite|number} for chaining
+ */
+Suite.prototype.timeout = function(ms) {
+ if (!arguments.length) {
+ return this._timeout;
+ }
+ if (ms.toString() === '0') {
+ this._enableTimeouts = false;
+ }
+ if (typeof ms === 'string') {
+ ms = milliseconds(ms);
+ }
+ debug('timeout %d', ms);
+ this._timeout = parseInt(ms, 10);
+ return this;
+};
+
+/**
+ * Set number of times to retry a failed test.
+ *
+ * @api private
+ * @param {number|string} n
+ * @return {Suite|number} for chaining
+ */
+Suite.prototype.retries = function(n) {
+ if (!arguments.length) {
+ return this._retries;
+ }
+ debug('retries %d', n);
+ this._retries = parseInt(n, 10) || 0;
+ return this;
+};
+
+/**
+ * Set timeout to `enabled`.
+ *
+ * @api private
+ * @param {boolean} enabled
+ * @return {Suite|boolean} self or enabled
+ */
+Suite.prototype.enableTimeouts = function(enabled) {
+ if (!arguments.length) {
+ return this._enableTimeouts;
+ }
+ debug('enableTimeouts %s', enabled);
+ this._enableTimeouts = enabled;
+ return this;
+};
+
+/**
+ * Set slow `ms` or short-hand such as "2s".
+ *
+ * @api private
+ * @param {number|string} ms
+ * @return {Suite|number} for chaining
+ */
+Suite.prototype.slow = function(ms) {
+ if (!arguments.length) {
+ return this._slow;
+ }
+ if (typeof ms === 'string') {
+ ms = milliseconds(ms);
+ }
+ debug('slow %d', ms);
+ this._slow = ms;
+ return this;
+};
+
+/**
+ * Sets whether to bail after first error.
+ *
+ * @api private
+ * @param {boolean} bail
+ * @return {Suite|number} for chaining
+ */
+Suite.prototype.bail = function(bail) {
+ if (!arguments.length) {
+ return this._bail;
+ }
+ debug('bail %s', bail);
+ this._bail = bail;
+ return this;
+};
+
+/**
+ * Check if this suite or its parent suite is marked as pending.
+ *
+ * @api private
+ */
+Suite.prototype.isPending = function() {
+ return this.pending || (this.parent && this.parent.isPending());
+};
+
+/**
+ * Run `fn(test[, done])` before running tests.
+ *
+ * @api private
+ * @param {string} title
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ */
+Suite.prototype.beforeAll = function(title, fn) {
+ if (this.isPending()) {
+ return this;
+ }
+ if (typeof title === 'function') {
+ fn = title;
+ title = fn.name;
+ }
+ title = '"before all" hook' + (title ? ': ' + title : '');
+
+ var hook = new Hook(title, fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.retries(this.retries());
+ hook.enableTimeouts(this.enableTimeouts());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._beforeAll.push(hook);
+ this.emit('beforeAll', hook);
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` after running tests.
+ *
+ * @api private
+ * @param {string} title
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ */
+Suite.prototype.afterAll = function(title, fn) {
+ if (this.isPending()) {
+ return this;
+ }
+ if (typeof title === 'function') {
+ fn = title;
+ title = fn.name;
+ }
+ title = '"after all" hook' + (title ? ': ' + title : '');
+
+ var hook = new Hook(title, fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.retries(this.retries());
+ hook.enableTimeouts(this.enableTimeouts());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._afterAll.push(hook);
+ this.emit('afterAll', hook);
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` before each test case.
+ *
+ * @api private
+ * @param {string} title
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ */
+Suite.prototype.beforeEach = function(title, fn) {
+ if (this.isPending()) {
+ return this;
+ }
+ if (typeof title === 'function') {
+ fn = title;
+ title = fn.name;
+ }
+ title = '"before each" hook' + (title ? ': ' + title : '');
+
+ var hook = new Hook(title, fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.retries(this.retries());
+ hook.enableTimeouts(this.enableTimeouts());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._beforeEach.push(hook);
+ this.emit('beforeEach', hook);
+ return this;
+};
+
+/**
+ * Run `fn(test[, done])` after each test case.
+ *
+ * @api private
+ * @param {string} title
+ * @param {Function} fn
+ * @return {Suite} for chaining
+ */
+Suite.prototype.afterEach = function(title, fn) {
+ if (this.isPending()) {
+ return this;
+ }
+ if (typeof title === 'function') {
+ fn = title;
+ title = fn.name;
+ }
+ title = '"after each" hook' + (title ? ': ' + title : '');
+
+ var hook = new Hook(title, fn);
+ hook.parent = this;
+ hook.timeout(this.timeout());
+ hook.retries(this.retries());
+ hook.enableTimeouts(this.enableTimeouts());
+ hook.slow(this.slow());
+ hook.ctx = this.ctx;
+ this._afterEach.push(hook);
+ this.emit('afterEach', hook);
+ return this;
+};
+
+/**
+ * Add a test `suite`.
+ *
+ * @api private
+ * @param {Suite} suite
+ * @return {Suite} for chaining
+ */
+Suite.prototype.addSuite = function(suite) {
+ suite.parent = this;
+ suite.timeout(this.timeout());
+ suite.retries(this.retries());
+ suite.enableTimeouts(this.enableTimeouts());
+ suite.slow(this.slow());
+ suite.bail(this.bail());
+ this.suites.push(suite);
+ this.emit('suite', suite);
+ return this;
+};
+
+/**
+ * Add a `test` to this suite.
+ *
+ * @api private
+ * @param {Test} test
+ * @return {Suite} for chaining
+ */
+Suite.prototype.addTest = function(test) {
+ test.parent = this;
+ test.timeout(this.timeout());
+ test.retries(this.retries());
+ test.enableTimeouts(this.enableTimeouts());
+ test.slow(this.slow());
+ test.ctx = this.ctx;
+ this.tests.push(test);
+ this.emit('test', test);
+ return this;
+};
+
+/**
+ * Return the full title generated by recursively concatenating the parent's
+ * full title.
+ *
+ * @api public
+ * @return {string}
+ */
+Suite.prototype.fullTitle = function() {
+ if (this.parent) {
+ var full = this.parent.fullTitle();
+ if (full) {
+ return full + ' ' + this.title;
+ }
+ }
+ return this.title;
+};
+
+/**
+ * Return the total number of tests.
+ *
+ * @api public
+ * @return {number}
+ */
+Suite.prototype.total = function() {
+ return utils.reduce(this.suites, function(sum, suite) {
+ return sum + suite.total();
+ }, 0) + this.tests.length;
+};
+
+/**
+ * Iterates through each suite recursively to find all tests. Applies a
+ * function in the format `fn(test)`.
+ *
+ * @api private
+ * @param {Function} fn
+ * @return {Suite}
+ */
+Suite.prototype.eachTest = function(fn) {
+ utils.forEach(this.tests, fn);
+ utils.forEach(this.suites, function(suite) {
+ suite.eachTest(fn);
+ });
+ return this;
+};
+
+/**
+ * This will run the root suite if we happen to be running in delayed mode.
+ */
+Suite.prototype.run = function run() {
+ if (this.root) {
+ this.emit('run');
+ }
+};
diff --git a/node_modules/mocha/lib/template.html b/node_modules/mocha/lib/template.html
new file mode 100644
index 000000000..36c5e0b69
--- /dev/null
+++ b/node_modules/mocha/lib/template.html
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Mocha</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link rel="stylesheet" href="mocha.css" />
+ </head>
+ <body>
+ <div id="mocha"></div>
+ <script src="mocha.js"></script>
+ <script>mocha.setup('bdd');</script>
+ <script src="tests.js"></script>
+ <script>
+ mocha.run();
+ </script>
+ </body>
+</html>
diff --git a/node_modules/mocha/lib/test.js b/node_modules/mocha/lib/test.js
new file mode 100644
index 000000000..a95cd31a4
--- /dev/null
+++ b/node_modules/mocha/lib/test.js
@@ -0,0 +1,44 @@
+/**
+ * Module dependencies.
+ */
+
+var Runnable = require('./runnable');
+var inherits = require('./utils').inherits;
+
+/**
+ * Expose `Test`.
+ */
+
+module.exports = Test;
+
+/**
+ * Initialize a new `Test` with the given `title` and callback `fn`.
+ *
+ * @api private
+ * @param {String} title
+ * @param {Function} fn
+ */
+function Test(title, fn) {
+ Runnable.call(this, title, fn);
+ this.pending = !fn;
+ this.type = 'test';
+}
+
+/**
+ * Inherit from `Runnable.prototype`.
+ */
+inherits(Test, Runnable);
+
+Test.prototype.clone = function() {
+ var test = new Test(this.title, this.fn);
+ test.timeout(this.timeout());
+ test.slow(this.slow());
+ test.enableTimeouts(this.enableTimeouts());
+ test.retries(this.retries());
+ test.currentRetry(this.currentRetry());
+ test.globals(this.globals());
+ test.parent = this.parent;
+ test.file = this.file;
+ test.ctx = this.ctx;
+ return test;
+};
diff --git a/node_modules/mocha/lib/utils.js b/node_modules/mocha/lib/utils.js
new file mode 100644
index 000000000..e5d214021
--- /dev/null
+++ b/node_modules/mocha/lib/utils.js
@@ -0,0 +1,750 @@
+/* eslint-env browser */
+
+/**
+ * Module dependencies.
+ */
+
+var basename = require('path').basename;
+var debug = require('debug')('mocha:watch');
+var exists = require('fs').existsSync || require('path').existsSync;
+var glob = require('glob');
+var join = require('path').join;
+var readdirSync = require('fs').readdirSync;
+var statSync = require('fs').statSync;
+var watchFile = require('fs').watchFile;
+var toISOString = require('to-iso-string');
+
+/**
+ * Ignored directories.
+ */
+
+var ignore = ['node_modules', '.git'];
+
+exports.inherits = require('util').inherits;
+
+/**
+ * Escape special characters in the given string of html.
+ *
+ * @api private
+ * @param {string} html
+ * @return {string}
+ */
+exports.escape = function(html) {
+ return String(html)
+ .replace(/&/g, '&amp;')
+ .replace(/"/g, '&quot;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;');
+};
+
+/**
+ * Array#forEach (<=IE8)
+ *
+ * @api private
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Object} scope
+ */
+exports.forEach = function(arr, fn, scope) {
+ for (var i = 0, l = arr.length; i < l; i++) {
+ fn.call(scope, arr[i], i);
+ }
+};
+
+/**
+ * Test if the given obj is type of string.
+ *
+ * @api private
+ * @param {Object} obj
+ * @return {boolean}
+ */
+exports.isString = function(obj) {
+ return typeof obj === 'string';
+};
+
+/**
+ * Array#map (<=IE8)
+ *
+ * @api private
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Object} scope
+ * @return {Array}
+ */
+exports.map = function(arr, fn, scope) {
+ var result = [];
+ for (var i = 0, l = arr.length; i < l; i++) {
+ result.push(fn.call(scope, arr[i], i, arr));
+ }
+ return result;
+};
+
+/**
+ * Array#indexOf (<=IE8)
+ *
+ * @api private
+ * @param {Array} arr
+ * @param {Object} obj to find index of
+ * @param {number} start
+ * @return {number}
+ */
+exports.indexOf = function(arr, obj, start) {
+ for (var i = start || 0, l = arr.length; i < l; i++) {
+ if (arr[i] === obj) {
+ return i;
+ }
+ }
+ return -1;
+};
+
+/**
+ * Array#reduce (<=IE8)
+ *
+ * @api private
+ * @param {Array} arr
+ * @param {Function} fn
+ * @param {Object} val Initial value.
+ * @return {*}
+ */
+exports.reduce = function(arr, fn, val) {
+ var rval = val;
+
+ for (var i = 0, l = arr.length; i < l; i++) {
+ rval = fn(rval, arr[i], i, arr);
+ }
+
+ return rval;
+};
+
+/**
+ * Array#filter (<=IE8)
+ *
+ * @api private
+ * @param {Array} arr
+ * @param {Function} fn
+ * @return {Array}
+ */
+exports.filter = function(arr, fn) {
+ var ret = [];
+
+ for (var i = 0, l = arr.length; i < l; i++) {
+ var val = arr[i];
+ if (fn(val, i, arr)) {
+ ret.push(val);
+ }
+ }
+
+ return ret;
+};
+
+/**
+ * Object.keys (<=IE8)
+ *
+ * @api private
+ * @param {Object} obj
+ * @return {Array} keys
+ */
+exports.keys = typeof Object.keys === 'function' ? Object.keys : function(obj) {
+ var keys = [];
+ var has = Object.prototype.hasOwnProperty; // for `window` on <=IE8
+
+ for (var key in obj) {
+ if (has.call(obj, key)) {
+ keys.push(key);
+ }
+ }
+
+ return keys;
+};
+
+/**
+ * Watch the given `files` for changes
+ * and invoke `fn(file)` on modification.
+ *
+ * @api private
+ * @param {Array} files
+ * @param {Function} fn
+ */
+exports.watch = function(files, fn) {
+ var options = { interval: 100 };
+ files.forEach(function(file) {
+ debug('file %s', file);
+ watchFile(file, options, function(curr, prev) {
+ if (prev.mtime < curr.mtime) {
+ fn(file);
+ }
+ });
+ });
+};
+
+/**
+ * Array.isArray (<=IE8)
+ *
+ * @api private
+ * @param {Object} obj
+ * @return {Boolean}
+ */
+var isArray = typeof Array.isArray === 'function' ? Array.isArray : function(obj) {
+ return Object.prototype.toString.call(obj) === '[object Array]';
+};
+
+exports.isArray = isArray;
+
+/**
+ * Buffer.prototype.toJSON polyfill.
+ *
+ * @type {Function}
+ */
+if (typeof Buffer !== 'undefined' && Buffer.prototype) {
+ Buffer.prototype.toJSON = Buffer.prototype.toJSON || function() {
+ return Array.prototype.slice.call(this, 0);
+ };
+}
+
+/**
+ * Ignored files.
+ *
+ * @api private
+ * @param {string} path
+ * @return {boolean}
+ */
+function ignored(path) {
+ return !~ignore.indexOf(path);
+}
+
+/**
+ * Lookup files in the given `dir`.
+ *
+ * @api private
+ * @param {string} dir
+ * @param {string[]} [ext=['.js']]
+ * @param {Array} [ret=[]]
+ * @return {Array}
+ */
+exports.files = function(dir, ext, ret) {
+ ret = ret || [];
+ ext = ext || ['js'];
+
+ var re = new RegExp('\\.(' + ext.join('|') + ')$');
+
+ readdirSync(dir)
+ .filter(ignored)
+ .forEach(function(path) {
+ path = join(dir, path);
+ if (statSync(path).isDirectory()) {
+ exports.files(path, ext, ret);
+ } else if (path.match(re)) {
+ ret.push(path);
+ }
+ });
+
+ return ret;
+};
+
+/**
+ * Compute a slug from the given `str`.
+ *
+ * @api private
+ * @param {string} str
+ * @return {string}
+ */
+exports.slug = function(str) {
+ return str
+ .toLowerCase()
+ .replace(/ +/g, '-')
+ .replace(/[^-\w]/g, '');
+};
+
+/**
+ * Strip the function definition from `str`, and re-indent for pre whitespace.
+ *
+ * @param {string} str
+ * @return {string}
+ */
+exports.clean = function(str) {
+ str = str
+ .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '')
+ .replace(/^function *\(.*\)\s*\{|\(.*\) *=> *\{?/, '')
+ .replace(/\s+\}$/, '');
+
+ var spaces = str.match(/^\n?( *)/)[1].length;
+ var tabs = str.match(/^\n?(\t*)/)[1].length;
+ var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm');
+
+ str = str.replace(re, '');
+
+ return exports.trim(str);
+};
+
+/**
+ * Trim the given `str`.
+ *
+ * @api private
+ * @param {string} str
+ * @return {string}
+ */
+exports.trim = function(str) {
+ return str.replace(/^\s+|\s+$/g, '');
+};
+
+/**
+ * Parse the given `qs`.
+ *
+ * @api private
+ * @param {string} qs
+ * @return {Object}
+ */
+exports.parseQuery = function(qs) {
+ return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair) {
+ var i = pair.indexOf('=');
+ var key = pair.slice(0, i);
+ var val = pair.slice(++i);
+
+ obj[key] = decodeURIComponent(val);
+ return obj;
+ }, {});
+};
+
+/**
+ * Highlight the given string of `js`.
+ *
+ * @api private
+ * @param {string} js
+ * @return {string}
+ */
+function highlight(js) {
+ return js
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/\/\/(.*)/gm, '<span class="comment">//$1</span>')
+ .replace(/('.*?')/gm, '<span class="string">$1</span>')
+ .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>')
+ .replace(/(\d+)/gm, '<span class="number">$1</span>')
+ .replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>')
+ .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>');
+}
+
+/**
+ * Highlight the contents of tag `name`.
+ *
+ * @api private
+ * @param {string} name
+ */
+exports.highlightTags = function(name) {
+ var code = document.getElementById('mocha').getElementsByTagName(name);
+ for (var i = 0, len = code.length; i < len; ++i) {
+ code[i].innerHTML = highlight(code[i].innerHTML);
+ }
+};
+
+/**
+ * If a value could have properties, and has none, this function is called,
+ * which returns a string representation of the empty value.
+ *
+ * Functions w/ no properties return `'[Function]'`
+ * Arrays w/ length === 0 return `'[]'`
+ * Objects w/ no properties return `'{}'`
+ * All else: return result of `value.toString()`
+ *
+ * @api private
+ * @param {*} value The value to inspect.
+ * @param {string} [type] The type of the value, if known.
+ * @returns {string}
+ */
+function emptyRepresentation(value, type) {
+ type = type || exports.type(value);
+
+ switch (type) {
+ case 'function':
+ return '[Function]';
+ case 'object':
+ return '{}';
+ case 'array':
+ return '[]';
+ default:
+ return value.toString();
+ }
+}
+
+/**
+ * Takes some variable and asks `Object.prototype.toString()` what it thinks it
+ * is.
+ *
+ * @api private
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
+ * @param {*} value The value to test.
+ * @returns {string}
+ * @example
+ * type({}) // 'object'
+ * type([]) // 'array'
+ * type(1) // 'number'
+ * type(false) // 'boolean'
+ * type(Infinity) // 'number'
+ * type(null) // 'null'
+ * type(new Date()) // 'date'
+ * type(/foo/) // 'regexp'
+ * type('type') // 'string'
+ * type(global) // 'global'
+ */
+exports.type = function type(value) {
+ if (value === undefined) {
+ return 'undefined';
+ } else if (value === null) {
+ return 'null';
+ } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) {
+ return 'buffer';
+ }
+ return Object.prototype.toString.call(value)
+ .replace(/^\[.+\s(.+?)\]$/, '$1')
+ .toLowerCase();
+};
+
+/**
+ * Stringify `value`. Different behavior depending on type of value:
+ *
+ * - If `value` is undefined or null, return `'[undefined]'` or `'[null]'`, respectively.
+ * - If `value` is not an object, function or array, return result of `value.toString()` wrapped in double-quotes.
+ * - If `value` is an *empty* object, function, or array, return result of function
+ * {@link emptyRepresentation}.
+ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of
+ * JSON.stringify().
+ *
+ * @api private
+ * @see exports.type
+ * @param {*} value
+ * @return {string}
+ */
+exports.stringify = function(value) {
+ var type = exports.type(value);
+
+ if (!~exports.indexOf(['object', 'array', 'function'], type)) {
+ if (type !== 'buffer') {
+ return jsonStringify(value);
+ }
+ var json = value.toJSON();
+ // Based on the toJSON result
+ return jsonStringify(json.data && json.type ? json.data : json, 2)
+ .replace(/,(\n|$)/g, '$1');
+ }
+
+ for (var prop in value) {
+ if (Object.prototype.hasOwnProperty.call(value, prop)) {
+ return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1');
+ }
+ }
+
+ return emptyRepresentation(value, type);
+};
+
+/**
+ * like JSON.stringify but more sense.
+ *
+ * @api private
+ * @param {Object} object
+ * @param {number=} spaces
+ * @param {number=} depth
+ * @returns {*}
+ */
+function jsonStringify(object, spaces, depth) {
+ if (typeof spaces === 'undefined') {
+ // primitive types
+ return _stringify(object);
+ }
+
+ depth = depth || 1;
+ var space = spaces * depth;
+ var str = isArray(object) ? '[' : '{';
+ var end = isArray(object) ? ']' : '}';
+ var length = typeof object.length === 'number' ? object.length : exports.keys(object).length;
+ // `.repeat()` polyfill
+ function repeat(s, n) {
+ return new Array(n).join(s);
+ }
+
+ function _stringify(val) {
+ switch (exports.type(val)) {
+ case 'null':
+ case 'undefined':
+ val = '[' + val + ']';
+ break;
+ case 'array':
+ case 'object':
+ val = jsonStringify(val, spaces, depth + 1);
+ break;
+ case 'boolean':
+ case 'regexp':
+ case 'symbol':
+ case 'number':
+ val = val === 0 && (1 / val) === -Infinity // `-0`
+ ? '-0'
+ : val.toString();
+ break;
+ case 'date':
+ var sDate;
+ if (isNaN(val.getTime())) { // Invalid date
+ sDate = val.toString();
+ } else {
+ sDate = val.toISOString ? val.toISOString() : toISOString(val);
+ }
+ val = '[Date: ' + sDate + ']';
+ break;
+ case 'buffer':
+ var json = val.toJSON();
+ // Based on the toJSON result
+ json = json.data && json.type ? json.data : json;
+ val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']';
+ break;
+ default:
+ val = (val === '[Function]' || val === '[Circular]')
+ ? val
+ : JSON.stringify(val); // string
+ }
+ return val;
+ }
+
+ for (var i in object) {
+ if (!Object.prototype.hasOwnProperty.call(object, i)) {
+ continue; // not my business
+ }
+ --length;
+ str += '\n ' + repeat(' ', space)
+ + (isArray(object) ? '' : '"' + i + '": ') // key
+ + _stringify(object[i]) // value
+ + (length ? ',' : ''); // comma
+ }
+
+ return str
+ // [], {}
+ + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end);
+}
+
+/**
+ * Test if a value is a buffer.
+ *
+ * @api private
+ * @param {*} value The value to test.
+ * @return {boolean} True if `value` is a buffer, otherwise false
+ */
+exports.isBuffer = function(value) {
+ return typeof Buffer !== 'undefined' && Buffer.isBuffer(value);
+};
+
+/**
+ * Return a new Thing that has the keys in sorted order. Recursive.
+ *
+ * If the Thing...
+ * - has already been seen, return string `'[Circular]'`
+ * - is `undefined`, return string `'[undefined]'`
+ * - is `null`, return value `null`
+ * - is some other primitive, return the value
+ * - is not a primitive or an `Array`, `Object`, or `Function`, return the value of the Thing's `toString()` method
+ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again.
+ * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()`
+ *
+ * @api private
+ * @see {@link exports.stringify}
+ * @param {*} value Thing to inspect. May or may not have properties.
+ * @param {Array} [stack=[]] Stack of seen values
+ * @return {(Object|Array|Function|string|undefined)}
+ */
+exports.canonicalize = function(value, stack) {
+ var canonicalizedObj;
+ /* eslint-disable no-unused-vars */
+ var prop;
+ /* eslint-enable no-unused-vars */
+ var type = exports.type(value);
+ function withStack(value, fn) {
+ stack.push(value);
+ fn();
+ stack.pop();
+ }
+
+ stack = stack || [];
+
+ if (exports.indexOf(stack, value) !== -1) {
+ return '[Circular]';
+ }
+
+ switch (type) {
+ case 'undefined':
+ case 'buffer':
+ case 'null':
+ canonicalizedObj = value;
+ break;
+ case 'array':
+ withStack(value, function() {
+ canonicalizedObj = exports.map(value, function(item) {
+ return exports.canonicalize(item, stack);
+ });
+ });
+ break;
+ case 'function':
+ /* eslint-disable guard-for-in */
+ for (prop in value) {
+ canonicalizedObj = {};
+ break;
+ }
+ /* eslint-enable guard-for-in */
+ if (!canonicalizedObj) {
+ canonicalizedObj = emptyRepresentation(value, type);
+ break;
+ }
+ /* falls through */
+ case 'object':
+ canonicalizedObj = canonicalizedObj || {};
+ withStack(value, function() {
+ exports.forEach(exports.keys(value).sort(), function(key) {
+ canonicalizedObj[key] = exports.canonicalize(value[key], stack);
+ });
+ });
+ break;
+ case 'date':
+ case 'number':
+ case 'regexp':
+ case 'boolean':
+ case 'symbol':
+ canonicalizedObj = value;
+ break;
+ default:
+ canonicalizedObj = value + '';
+ }
+
+ return canonicalizedObj;
+};
+
+/**
+ * Lookup file names at the given `path`.
+ *
+ * @api public
+ * @param {string} path Base path to start searching from.
+ * @param {string[]} extensions File extensions to look for.
+ * @param {boolean} recursive Whether or not to recurse into subdirectories.
+ * @return {string[]} An array of paths.
+ */
+exports.lookupFiles = function lookupFiles(path, extensions, recursive) {
+ var files = [];
+ var re = new RegExp('\\.(' + extensions.join('|') + ')$');
+
+ if (!exists(path)) {
+ if (exists(path + '.js')) {
+ path += '.js';
+ } else {
+ files = glob.sync(path);
+ if (!files.length) {
+ throw new Error("cannot resolve path (or pattern) '" + path + "'");
+ }
+ return files;
+ }
+ }
+
+ try {
+ var stat = statSync(path);
+ if (stat.isFile()) {
+ return path;
+ }
+ } catch (err) {
+ // ignore error
+ return;
+ }
+
+ readdirSync(path).forEach(function(file) {
+ file = join(path, file);
+ try {
+ var stat = statSync(file);
+ if (stat.isDirectory()) {
+ if (recursive) {
+ files = files.concat(lookupFiles(file, extensions, recursive));
+ }
+ return;
+ }
+ } catch (err) {
+ // ignore error
+ return;
+ }
+ if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') {
+ return;
+ }
+ files.push(file);
+ });
+
+ return files;
+};
+
+/**
+ * Generate an undefined error with a message warning the user.
+ *
+ * @return {Error}
+ */
+
+exports.undefinedError = function() {
+ return new Error('Caught undefined error, did you throw without specifying what?');
+};
+
+/**
+ * Generate an undefined error if `err` is not defined.
+ *
+ * @param {Error} err
+ * @return {Error}
+ */
+
+exports.getError = function(err) {
+ return err || exports.undefinedError();
+};
+
+/**
+ * @summary
+ * This Filter based on `mocha-clean` module.(see: `github.com/rstacruz/mocha-clean`)
+ * @description
+ * When invoking this function you get a filter function that get the Error.stack as an input,
+ * and return a prettify output.
+ * (i.e: strip Mocha and internal node functions from stack trace).
+ * @returns {Function}
+ */
+exports.stackTraceFilter = function() {
+ // TODO: Replace with `process.browser`
+ var slash = '/';
+ var is = typeof document === 'undefined' ? { node: true } : { browser: true };
+ var cwd = is.node
+ ? process.cwd() + slash
+ : (typeof location === 'undefined' ? window.location : location).href.replace(/\/[^\/]*$/, '/');
+
+ function isMochaInternal(line) {
+ return (~line.indexOf('node_modules' + slash + 'mocha' + slash))
+ || (~line.indexOf('components' + slash + 'mochajs' + slash))
+ || (~line.indexOf('components' + slash + 'mocha' + slash))
+ || (~line.indexOf(slash + 'mocha.js'));
+ }
+
+ function isNodeInternal(line) {
+ return (~line.indexOf('(timers.js:'))
+ || (~line.indexOf('(events.js:'))
+ || (~line.indexOf('(node.js:'))
+ || (~line.indexOf('(module.js:'))
+ || (~line.indexOf('GeneratorFunctionPrototype.next (native)'))
+ || false;
+ }
+
+ return function(stack) {
+ stack = stack.split('\n');
+
+ stack = exports.reduce(stack, function(list, line) {
+ if (isMochaInternal(line)) {
+ return list;
+ }
+
+ if (is.node && isNodeInternal(line)) {
+ return list;
+ }
+
+ // Clean up cwd(absolute)
+ if (/\(?.+:\d+:\d+\)?$/.test(line)) {
+ line = line.replace(cwd, '');
+ }
+
+ list.push(line);
+ return list;
+ }, []);
+
+ return stack.join('\n');
+ };
+};