diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000000..4b5665da7d --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +root = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore index fbb64d6ad6..90dbb6975a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,2 @@ -.DS_Store +_site node_modules -*.sock -testing diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000000..4a9d77fc56 --- /dev/null +++ b/Gemfile @@ -0,0 +1 @@ +gem 'github-pages' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000000..22d13c3ee6 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,127 @@ +GEM + specs: + RedCloth (4.2.9) + activesupport (4.2.1) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + blankslate (2.1.2.4) + celluloid (0.16.0) + timers (~> 4.0.0) + classifier-reborn (2.0.3) + fast-stemmer (~> 1.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.9.1.1) + colorator (0.1) + execjs (2.5.2) + fast-stemmer (1.0.2) + ffi (1.9.8) + gemoji (2.1.0) + github-pages (37) + RedCloth (= 4.2.9) + github-pages-health-check (~> 0.2) + jekyll (= 2.4.0) + jekyll-coffeescript (= 1.0.1) + jekyll-feed (= 0.3.0) + jekyll-mentions (= 0.2.1) + jekyll-redirect-from (= 0.8.0) + jekyll-sass-converter (= 1.2.0) + jekyll-sitemap (= 0.8.1) + jemoji (= 0.4.0) + kramdown (= 1.5.0) + liquid (= 2.6.2) + maruku (= 0.7.0) + mercenary (~> 0.3) + pygments.rb (= 0.6.1) + rdiscount (= 2.1.7) + redcarpet (= 3.1.2) + terminal-table (~> 1.4) + github-pages-health-check (0.2.2) + net-dns (~> 0.6) + public_suffix (~> 1.4) + hitimes (1.2.2) + html-pipeline (1.9.0) + activesupport (>= 2) + nokogiri (~> 1.4) + i18n (0.7.0) + jekyll (2.4.0) + classifier-reborn (~> 2.0) + colorator (~> 0.1) + jekyll-coffeescript (~> 1.0) + jekyll-gist (~> 1.0) + jekyll-paginate (~> 1.0) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 2.6.1) + mercenary (~> 0.3.3) + pygments.rb (~> 0.6.0) + redcarpet (~> 3.1) + safe_yaml (~> 1.0) + toml (~> 0.1.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-feed (0.3.0) + jekyll-gist (1.2.1) + jekyll-mentions (0.2.1) + html-pipeline (~> 1.9.0) + jekyll (~> 2.0) + jekyll-paginate (1.1.0) + jekyll-redirect-from (0.8.0) + jekyll (>= 2.0) + jekyll-sass-converter (1.2.0) + sass (~> 3.2) + jekyll-sitemap (0.8.1) + jekyll-watch (1.2.1) + listen (~> 2.7) + jemoji (0.4.0) + gemoji (~> 2.0) + html-pipeline (~> 1.9) + jekyll (~> 2.0) + json (1.8.2) + kramdown (1.5.0) + liquid (2.6.2) + listen (2.10.0) + celluloid (~> 0.16.0) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + maruku (0.7.0) + mercenary (0.3.5) + mini_portile (0.6.2) + minitest (5.6.0) + net-dns (0.8.0) + nokogiri (1.6.6.2) + mini_portile (~> 0.6.0) + parslet (1.5.0) + blankslate (~> 2.0) + posix-spawn (0.3.11) + public_suffix (1.5.1) + pygments.rb (0.6.1) + posix-spawn (~> 0.3.6) + yajl-ruby (~> 1.2.0) + rb-fsevent (0.9.4) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + rdiscount (2.1.7) + redcarpet (3.1.2) + safe_yaml (1.0.4) + sass (3.4.13) + terminal-table (1.4.5) + thread_safe (0.3.5) + timers (4.0.1) + hitimes + toml (0.1.2) + parslet (~> 1.5.0) + tzinfo (1.2.2) + thread_safe (~> 0.1) + yajl-ruby (1.2.1) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages diff --git a/Makefile b/Makefile deleted file mode 100644 index 51fbe9831a..0000000000 --- a/Makefile +++ /dev/null @@ -1,10 +0,0 @@ - -index.html: head.html foot.html index.md - @markdown < index.md \ - | cat head.html - foot.html \ - > $@ - -clean: - rm -f index.html - -.PHONY: clean \ No newline at end of file diff --git a/README.md b/README.md index a89c99485d..38de2ad63a 100644 --- a/README.md +++ b/README.md @@ -1,45 +1,27 @@ -# mocha: How to Build the Site +# [mochajs.org](http://mochajs.org): How to Build the Site -So you wanna build the site? +*So you wanna build the site?* -## Requirements +mochajs.org is now built using [Jekyll](http://jekyllrb.com), the popular static site generator. -There's two: +## Prerequisites -1. [make](http://www.gnu.org/software/make/) -2. [markdown](http://daringfireball.net/projects/markdown/) +1. Some recent version of Ruby +2. A recent version of Node.JS +3. [Bundler](http://bundler.io) -### Mac OS X + To install Bundler, after installing Ruby, execute `gem install bundler`. + +4. Now, execute `npm install`. This will install Jekyll and a bunch of other + crap we need. + +5. To build, execute `npm run-script build`. -Install `markdown` via Homebrew: +For more information, refer to the [Jekyll Docs](http://jekyllrb.com/docs/home/) and [GitHub's Tutorial](https://help.github.com/articles/using-jekyll-with-pages/) on the subject. -```sh -brew install markdown -``` +## Notes -Or download from [here](http://daringfireball.net/projects/markdown/). - -Celebrate with tequila! Or try to build first. Probably want to build first. - -### Linux - -#### Ubuntu 14.04 - -1. `sudo apt-get install build-essential` to install make. -2. `sudo apt-get install markdown` to install markdown. -3. That seems to do it. It's just a Perl script, so you can [get it from here](http://daringfireball.net/projects/markdown/) otherwise. - -### Windows - -*To be filled in by somebody using Windows* - -## Building - -Execute: - -``` -make clean && make -``` - -You should now have an updated `index.html`. Open it in your browser and proceed to tweak it until it's correct, because the compiler seem a little wonky. +- The TOC is generated with [marked-toc](https://www.npmjs.com/package/marked-toc). +- The `id` attributes for all of the headers are generated with JavaScript. +- The `_site` directory is where the generated site lives. It is *not* under version control, because GitHub Pages generates it for us. diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000000..c46cbc71d9 --- /dev/null +++ b/_config.yml @@ -0,0 +1,10 @@ +url: http://mochajs.org +markdown: redcarpet +highlighter: pygments +exclude: + - node_modules + - README.md + - Gemfile* + - package.json + - CNAME + diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 0000000000..0837114608 --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,28 @@ + diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 0000000000..097bf8343a --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,12 @@ + + + Mocha - the fun, simple, flexible JavaScript test framework + + + + + + + diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 0000000000..71eb2f0287 --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,4 @@ +
+

Mocha

+

simple, flexible, fun

+
diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 0000000000..f71fd1faff --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,18 @@ + + + + {% include head.html %} + + + + {% include header.html %} + +
+ {{ content }} +
+ + {% include footer.html %} + + + + diff --git a/_mocha.js b/_mocha.js deleted file mode 100644 index 095a2f9afc..0000000000 --- a/_mocha.js +++ /dev/null @@ -1,4057 +0,0 @@ - -// CommonJS require() - -function require(p){ - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - } - -require.modules = {}; - -require.resolve = function (path){ - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }; - -require.register = function (path, fn){ - require.modules[path] = fn; - }; - -require.relative = function (parent) { - return function(p){ - if ('.' != p.charAt(0)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }; - - -require.register("browser/debug.js", function(module, exports, require){ - -module.exports = function(type){ - return function(){ - - } -}; -}); // module: browser/debug.js - -require.register("browser/diff.js", function(module, exports, require){ - -}); // module: browser/diff.js - -require.register("browser/events.js", function(module, exports, require){ - -/** - * Module exports. - */ - -exports.EventEmitter = EventEmitter; - -/** - * Check if `obj` is an array. - */ - -function isArray(obj) { - return '[object Array]' == {}.toString.call(obj); -} - -/** - * Event emitter constructor. - * - * @api public - */ - -function EventEmitter(){}; - -/** - * Adds a listener. - * - * @api public - */ - -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 - */ - -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; -}; - -/** - * Removes a listener. - * - * @api public - */ - -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; -}; - -/** - * Removes all listeners for an event. - * - * @api public - */ - -EventEmitter.prototype.removeAllListeners = function (name) { - if (name === undefined) { - this.$events = {}; - return this; - } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; -}; - -/** - * Gets all listeners for a certain event. - * - * @api public - */ - -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]; -}; - -/** - * Emits an event. - * - * @api public - */ - -EventEmitter.prototype.emit = function (name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = [].slice.call(arguments, 1); - - if ('function' == typeof handler) { - 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; -}; -}); // module: browser/events.js - -require.register("browser/fs.js", function(module, exports, require){ - -}); // module: browser/fs.js - -require.register("browser/path.js", function(module, exports, require){ - -}); // module: browser/path.js - -require.register("browser/progress.js", function(module, exports, require){ - -/** - * 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 `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.size = function(n){ - this._size = n; - return this; -}; - -/** - * Set text to `str`. - * - * @param {String} str - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.text = function(str){ - this._text = str; - return this; -}; - -/** - * Set font size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.fontSize = function(n){ - this._fontSize = n; - return this; -}; - -/** - * Set font `family`. - * - * @param {String} family - * @return {Progress} for chaining - */ - -Progress.prototype.font = function(family){ - this._font = family; - return this; -}; - -/** - * Update percentage to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - */ - -Progress.prototype.update = function(n){ - this.percent = n; - return this; -}; - -/** - * Draw on `ctx`. - * - * @param {CanvasRenderingContext2d} ctx - * @return {Progress} for chaining - */ - -Progress.prototype.draw = function(ctx){ - var percent = Math.min(this.percent, 100) - , size = this._size - , half = size / 2 - , x = half - , y = half - , rad = half - 1 - , 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) + '%' - , w = ctx.measureText(text).width; - - ctx.fillText( - text - , x - w / 2 + 1 - , y + fontSize / 2 - 1); - - return this; -}; - -}); // module: browser/progress.js - -require.register("browser/tty.js", function(module, exports, require){ - -exports.isatty = function(){ - return true; -}; - -exports.getWindowSize = function(){ - return [window.innerHeight, window.innerWidth]; -}; -}); // module: browser/tty.js - -require.register("context.js", function(module, exports, require){ - -/** - * Expose `Context`. - */ - -module.exports = Context; - -/** - * Initialize a new `Context`. - * - * @api private - */ - -function Context(){} - -/** - * Set the context `Runnable` to `runnable`. - * - * @param {Runnable} runnable - * @return {Context} - * @api private - */ - -Context.prototype.runnable = function(runnable){ - this._runnable = runnable; - return this; -}; - -/** - * Set test timeout `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.timeout = function(ms){ - this._runnable.timeout(ms); - return this; -}; - -/** - * Inspect the context void of `._runnable`. - * - * @return {String} - * @api private - */ - -Context.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - return '_runnable' == key - ? undefined - : val; - }, 2); -}; - -}); // module: context.js - -require.register("hook.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * 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`. - */ - -Hook.prototype = new Runnable; -Hook.prototype.constructor = Hook; - - -}); // module: hook.js - -require.register("interfaces/bdd.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * 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(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context){ - - // noop variants - - context.xdescribe = function(){}; - context.xit = function(){}; - - /** - * Execute before running tests. - */ - - context.before = function(fn){ - suites[0].beforeAll(fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(fn){ - suites[0].afterAll(fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(fn){ - suites[0].beforeEach(fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(fn){ - suites[0].afterEach(fn); - }; - - /** - * 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); - suites.unshift(suite); - fn(); - suites.shift(); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.it = context.specify = function(title, fn){ - suites[0].addTest(new Test(title, fn)); - }; - }); -}; - -}); // module: interfaces/bdd.js - -require.register("interfaces/exports.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * TDD-style 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(){ - * - * } - * } - * }; - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('require', visit); - - function visit(obj) { - var suite; - for (var key in obj) { - if ('function' == typeof obj[key]) { - 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: - suites[0].addTest(new Test(key, fn)); - } - } else { - var suite = Suite.create(suites[0], key); - suites.unshift(suite); - visit(obj[key]); - suites.shift(); - } - } - } -}; -}); // module: interfaces/exports.js - -require.register("interfaces/index.js", function(module, exports, require){ - -exports.bdd = require('./bdd'); -exports.tdd = require('./tdd'); -exports.qunit = require('./qunit'); -exports.exports = require('./exports'); - -}); // module: interfaces/index.js - -require.register("interfaces/qunit.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * 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); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context){ - - /** - * Execute before running tests. - */ - - context.before = function(fn){ - suites[0].beforeAll(fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(fn){ - suites[0].afterAll(fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(fn){ - suites[0].beforeEach(fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(fn){ - suites[0].afterEach(fn); - }; - - /** - * Describe a "suite" with the given `title`. - */ - - context.suite = function(title){ - if (suites.length > 1) suites.shift(); - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - suites[0].addTest(new Test(title, fn)); - }; - }); -}; - -}); // module: interfaces/qunit.js - -require.register("interfaces/tdd.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * 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(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context){ - - /** - * Execute before each test case. - */ - - context.setup = function(fn){ - suites[0].beforeEach(fn); - }; - - /** - * Execute after each test case. - */ - - context.teardown = function(fn){ - suites[0].afterEach(fn); - }; - - /** - * Execute before the suite. - */ - - context.suiteSetup = function(fn){ - suites[0].beforeAll(fn); - }; - - /** - * Execute after the suite. - */ - - context.suiteTeardown = function(fn){ - suites[0].afterAll(fn); - }; - - /** - * 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); - suites.unshift(suite); - fn(); - suites.shift(); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - suites[0].addTest(new Test(title, fn)); - }; - }); -}; - -}); // module: interfaces/tdd.js - -require.register("mocha.js", function(module, exports, require){ -/*! - * mocha - * Copyright(c) 2011 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var path = require('browser/path'); - -/** - * Expose `Mocha`. - */ - -exports = module.exports = Mocha; - -/** - * Library version. - */ - -exports.version = '1.1.0'; - -/** - * Expose internals. - */ - -exports.utils = require('./utils'); -exports.interfaces = require('./interfaces'); -exports.reporters = require('./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. - * - * @param {String} name - * @return {String} - * @api private - */ - -function image(name) { - return __dirname + '/../images/' + name + '.png'; -} - -/** - * Setup mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `ignoreLeaks` ignore global leaks - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public - */ - -function Mocha(options) { - options = options || {}; - this.files = []; - this.options = options; - this.grep(options.grep); - this.suite = new exports.Suite('', new exports.Context); - this.ui(options.ui); - this.reporter(options.reporter); - if (options.timeout) this.suite.timeout(options.timeout); -} - -/** - * Add test `file`. - * - * @param {String} file - * @api public - */ - -Mocha.prototype.addFile = function(file){ - this.files.push(file); - return this; -}; - -/** - * Set reporter to `name`, defaults to "dot". - * - * @param {String} name - * @api public - */ - -Mocha.prototype.reporter = function(name){ - name = name || 'dot'; - this._reporter = require('./reporters/' + name); - if (!this._reporter) throw new Error('invalid reporter "' + name + '"'); - return this; -}; - -/** - * Set test UI `name`, defaults to "bdd". - * - * @param {String} bdd - * @api public - */ - -Mocha.prototype.ui = function(name){ - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) throw new Error('invalid interface "' + name + '"'); - this._ui = this._ui(this.suite); - return this; -}; - -/** - * Load registered files. - * - * @api private - */ - -Mocha.prototype.loadFiles = function(){ - var suite = this.suite; - this.files.forEach(function(file){ - file = path.resolve(file); - suite.emit('pre-require', global, file); - suite.emit('require', require(file), file); - suite.emit('post-require', global, file); - }); -}; - -/** - * 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 for to the options object - * - * @param {RegExp} or {String} re - * @return {Mocha} - * @api public - */ - -Mocha.prototype.grep = function(re){ - this.options.grep = 'string' == typeof re - ? new RegExp(re) - : re; - return this; -}; - -/** - * Run tests and invoke `fn()` when complete. - * - * @param {Function} fn - * @return {Runner} - * @api public - */ - -Mocha.prototype.run = function(fn){ - this.loadFiles(); - var suite = this.suite; - var options = this.options; - var runner = new exports.Runner(suite); - var reporter = new this._reporter(runner); - runner.ignoreLeaks = options.ignoreLeaks; - if (options.grep) runner.grep(options.grep); - if (options.globals) runner.globals(options.globals); - if (options.growl) this.growl(runner, reporter); - return runner.run(fn); -}; - -}); // module: mocha.js - -require.register("reporters/base.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var tty = require('browser/tty') - , diff = require('browser/diff'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Check if both stdio streams are associated with a tty. - */ - -var isatty = tty.isatty(1) && tty.isatty(2); - -/** - * Expose `Base`. - */ - -exports = module.exports = Base; - -/** - * Enable coloring by default. - */ - -exports.useColors = isatty; - -/** - * 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': 42 - , 'diff removed': 41 -}; - -/** - * 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 str; - return '\033[' + exports.colors[type] + 'm' + str + '\033[0m'; -}; - -/** - * Expose term window size, with some - * defaults for when stderr is not a tty. - */ - -exports.window = { - width: isatty - ? process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1] - : 75 -}; - -/** - * Expose some basic cursor interactions - * that are common among reporters. - */ - -exports.cursor = { - hide: function(){ - process.stdout.write('\033[?25l'); - }, - - show: function(){ - process.stdout.write('\033[?25h'); - }, - - deleteLine: function(){ - process.stdout.write('\033[2K'); - }, - - beginningOfLine: function(){ - process.stdout.write('\033[0G'); - }, - - CR: function(){ - exports.cursor.deleteLine(); - exports.cursor.beginningOfLine(); - } -}; - -/** - * A test is considered slow if it - * exceeds the following value in milliseconds. - */ - -exports.slow = 75; - -/** - * Outut the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ - -exports.list = function(failures){ - console.error(); - 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 err = test.err - , message = err.message || '' - , stack = err.stack || message - , index = stack.indexOf(message) + message.length - , msg = stack.slice(0, index) - , actual = err.actual - , expected = err.expected; - - // actual / expected diff - if ('string' == typeof actual && 'string' == typeof expected) { - var len = Math.max(actual.length, expected.length); - - if (len < 20) msg = errorDiff(err, 'Chars'); - else msg = errorDiff(err, 'Words'); - - // 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, ' '); - - fmt = color('error title', ' %s) %s:\n%s') - + color('error stack', '\n%s\n'); - } - - // indent stack trace without msg - stack = stack.slice(index ? index + 1 : index) - .replace(/^/gm, ' '); - - console.error(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 self = this - , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } - , failures = this.failures = []; - - if (!runner) return; - this.runner = runner; - - 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(test){ - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test){ - stats.passes = stats.passes || 0; - - var medium = exports.slow / 2; - test.speed = test.duration > exports.slow - ? 'slow' - : test.duration > medium - ? 'medium' - : '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 - , fmt - , tests; - - console.log(); - - function pluralize(n) { - return 1 == n ? 'test' : 'tests'; - } - - // failure - if (stats.failures) { - fmt = color('bright fail', ' ✖') - + color('fail', ' %d of %d %s failed') - + color('light', ':') - - console.error(fmt, - stats.failures, - this.runner.total, - pluralize(this.runner.total)); - - Base.list(this.failures); - console.error(); - return; - } - - // pass - fmt = color('bright pass', ' ✔') - + color('green', ' %d %s complete') - + color('light', ' (%dms)'); - - console.log(fmt, - stats.tests || 0, - pluralize(stats.tests), - stats.duration); - - // pending - if (stats.pending) { - fmt = color('pending', ' •') - + color('pending', ' %d %s pending'); - - console.log(fmt, stats.pending, pluralize(stats.pending)); - } - - console.log(); -}; - -/** - * Pad the given `str` to `len`. - * - * @param {String} str - * @param {String} len - * @return {String} - * @api private - */ - -function pad(str, len) { - str = String(str); - return Array(len - str.length + 1).join(' ') + str; -} - -/** - * Return a character diff for `err`. - * - * @param {Error} err - * @return {String} - * @api private - */ - -function errorDiff(err, type) { - return diff['diff' + type](err.actual, err.expected).map(function(str){ - if (/^(\n+)$/.test(str.value)) str.value = Array(++RegExp.$1.length).join(''); - if (str.added) return colorLines('diff added', str.value); - if (str.removed) return colorLines('diff removed', str.value); - return str.value; - }).join(''); -} - -/** - * Color lines for `str`, using the color `name`. - * - * @param {String} name - * @param {String} str - * @return {String} - * @api private - */ - -function colorLines(name, str) { - return str.split('\n').map(function(str){ - return color(name, str); - }).join('\n'); -} - -}); // module: reporters/base.js - -require.register("reporters/doc.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , 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 self = this - , stats = this.stats - , total = runner.total - , indents = 2; - - function indent() { - return Array(indents).join(' '); - } - - runner.on('suite', function(suite){ - if (suite.root) return; - ++indents; - console.log('%s
', indent()); - ++indents; - console.log('%s

%s

', indent(), suite.title); - console.log('%s
', indent()); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - console.log('%s
', indent()); - --indents; - console.log('%s
', indent()); - --indents; - }); - - runner.on('pass', function(test){ - console.log('%s
%s
', indent(), test.title); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
%s
', indent(), code); - }); -} - -}); // module: reporters/doc.js - -require.register("reporters/dot.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = Dot; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Dot(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , n = 0; - - runner.on('start', function(){ - process.stdout.write('\n '); - }); - - runner.on('pending', function(test){ - process.stdout.write(color('pending', '.')); - }); - - runner.on('pass', function(test){ - if (++n % width == 0) process.stdout.write('\n '); - if ('slow' == test.speed) { - process.stdout.write(color('bright yellow', '.')); - } else { - process.stdout.write(color(test.speed, '.')); - } - }); - - runner.on('fail', function(test, err){ - if (++n % width == 0) process.stdout.write('\n '); - process.stdout.write(color('fail', '.')); - }); - - runner.on('end', function(){ - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -Dot.prototype = new Base; -Dot.prototype.constructor = Dot; - -}); // module: reporters/dot.js - -require.register("reporters/html-cov.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var JSONCov = require('./json-cov') - , fs = require('browser/fs'); - -/** - * Expose `HTMLCov`. - */ - -exports = module.exports = HTMLCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTMLCov(runner) { - var jade = require('jade') - , file = __dirname + '/templates/coverage.jade' - , str = fs.readFileSync(file, 'utf8') - , fn = jade.compile(str, { filename: file }) - , self = this; - - JSONCov.call(this, runner, false); - - runner.on('end', function(){ - process.stdout.write(fn({ - cov: self.cov - , coverageClass: coverageClass - })); - }); -} - -/** - * Return coverage class for `n`. - * - * @return {String} - * @api private - */ - -function coverageClass(n) { - if (n >= 75) return 'high'; - if (n >= 50) return 'medium'; - if (n >= 25) return 'low'; - return 'terrible'; -} -}); // module: reporters/html-cov.js - -require.register("reporters/html.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , Progress = require('../browser/progress') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `Doc`. - */ - -exports = module.exports = HTML; - -/** - * Stats template. - */ - -var statsTemplate = ''; - -/** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTML(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , root = document.getElementById('mocha') - , stat = fragment(statsTemplate) - , items = stat.getElementsByTagName('li') - , passes = items[1].getElementsByTagName('em')[0] - , failures = items[2].getElementsByTagName('em')[0] - , duration = items[3].getElementsByTagName('em')[0] - , canvas = stat.getElementsByTagName('canvas')[0] - , report = fragment('') - , stack = [report] - , progress - , ctx - - if (canvas.getContext) { - ctx = canvas.getContext('2d'); - progress = new Progress; - } - - if (!root) return error('#mocha div missing, add it to your document'); - - root.appendChild(stat); - root.appendChild(report); - - if (progress) progress.size(40); - - runner.on('suite', function(suite){ - if (suite.root) return; - - // suite - var url = location.protocol + '//' + location.host + location.pathname + '?grep=^' + utils.escapeRegexp(suite.fullTitle()); - var el = fragment('
  • %s

  • ', url, 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('fail', function(test, err){ - if ('hook' == test.type || err.uncaught) runner.emit('test end', test); - }); - - runner.on('test end', function(test){ - // TODO: add to stats - var percent = stats.tests / 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)); - - // test - if ('passed' == test.state) { - var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration); - } else if (test.pending) { - var el = fragment('
  • %e

  • ', test.title); - } else { - var el = fragment('
  • %e

  • ', test.title); - var str = test.err.stack || test.err.toString(); - - // FF / Opera do not add the message - if (!~str.indexOf(test.err.message)) { - str = test.err.message + '\n' + str; - } - - // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we - // check for the result of the stringifying. - if ('[object Error]' == str) str = test.err.message; - - // Safari doesn't give you a stack. Let's at least provide a source line. - if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { - str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; - } - - el.appendChild(fragment('
    %e
    ', str)); - } - - // toggle code - var h2 = el.getElementsByTagName('h2')[0]; - - on(h2, 'click', function(){ - pre.style.display = 'none' == pre.style.display - ? 'block' - : 'none'; - }); - - // code - // TODO: defer - if (!test.pending) { - var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); - el.appendChild(pre); - pre.style.display = 'none'; - } - - stack[0].appendChild(el); - }); -} - -/** - * Display error `msg`. - */ - -function error(msg) { - document.body.appendChild(fragment('
    %s
    ', msg)); -} - -/** - * Return a DOM fragment from `html`. - */ - -function fragment(html) { - var args = arguments - , div = document.createElement('div') - , i = 1; - - div.innerHTML = html.replace(/%([se])/g, function(_, type){ - switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); - } - }); - - return div.firstChild; -} - -/** - * Set `el` text to `str`. - */ - -function text(el, str) { - if (el.textContent) { - el.textContent = str; - } else { - el.innerText = str; - } -} - -/** - * 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); - } -} -}); // module: reporters/html.js - -require.register("reporters/index.js", function(module, exports, require){ - -exports.Base = require('./base'); -exports.Dot = require('./dot'); -exports.Doc = require('./doc'); -exports.TAP = require('./tap'); -exports.JSON = require('./json'); -exports.HTML = require('./html'); -exports.List = require('./list'); -exports.Min = require('./min'); -exports.Spec = require('./spec'); -exports.Progress = require('./progress'); -exports.Landing = require('./landing'); -exports.JSONCov = require('./json-cov'); -exports.HTMLCov = require('./html-cov'); -exports.JSONStream = require('./json-stream'); -exports.XUnit = require('./xunit') -exports.Teamcity = require('./teamcity') - -}); // module: reporters/index.js - -require.register("reporters/json-cov.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `JSONCov`. - */ - -exports = module.exports = JSONCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @param {Boolean} output - * @api public - */ - -function JSONCov(runner, output) { - var self = this - , output = 1 == arguments.length ? true : output; - - Base.call(this, runner); - - var tests = [] - , failures = [] - , 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. - * - * @param {Object} cov - * @return {Object} - * @api private - */ - -function map(cov) { - var ret = { - instrumentation: 'node-jscoverage' - , sloc: 0 - , hits: 0 - , misses: 0 - , coverage: 0 - , files: [] - }; - - for (var filename in cov) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; - } - - 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. - * - * @param {String} filename name of the source file - * @param {Object} data jscoverage coverage data - * @return {Object} - * @api private - */ - -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. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} - -}); // module: reporters/json-cov.js - -require.register("reporters/json-stream.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , 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){ - console.log(JSON.stringify(['fail', clean(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. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} -}); // module: reporters/json-stream.js - -require.register("reporters/json.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `JSON`. - */ - -exports = module.exports = JSONReporter; - -/** - * Initialize a new `JSON` reporter. - * - * @param {Runner} runner - * @api public - */ - -function JSONReporter(runner) { - var self = this; - Base.call(this, runner); - - var tests = [] - , failures = [] - , 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 obj = { - stats: self.stats - , tests: tests.map(clean) - , failures: failures.map(clean) - , passes: passes.map(clean) - }; - - process.stdout.write(JSON.stringify(obj, null, 2)); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} -}); // module: reporters/json.js - -require.register("reporters/landing.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , 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. - * - * @param {Runner} runner - * @api public - */ - -function Landing(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , total = runner.total - , stream = process.stdout - , plane = color('plane', '✈') - , crashed = -1 - , n = 0; - - function runway() { - var buf = Array(width).join('-'); - return ' ' + color('runway', buf); - } - - runner.on('start', function(){ - stream.write('\n '); - cursor.hide(); - }); - - runner.on('test end', function(test){ - // check if the plane crashed - var col = -1 == crashed - ? width * ++n / total | 0 - : crashed; - - // show the crash - if ('failed' == test.state) { - plane = color('plane crash', '✈'); - crashed = col; - } - - // render landing strip - stream.write('\033[4F\n\n'); - 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('\033[0m'); - }); - - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -Landing.prototype = new Base; -Landing.prototype.constructor = Landing; - -}); // module: reporters/landing.js - -require.register("reporters/list.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , 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', ' ✓') - + color('pass', ' %s: ') - + color(test.speed, '%dms'); - cursor.CR(); - console.log(fmt, test.fullTitle(), test.duration); - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -List.prototype = new Base; -List.prototype.constructor = List; - - -}); // module: reporters/list.js - -require.register("reporters/markdown.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Markdown`. - */ - -exports = module.exports = Markdown; - -/** - * Initialize a new `Markdown` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Markdown(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , level = 0 - , buf = ''; - - function title(str) { - return Array(level).join('#') + ' ' + str; - } - - function indent() { - return Array(level).join(' '); - } - - function mapTOC(suite, obj) { - var ret = obj; - obj = obj[suite.title] = obj[suite.title] || { 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 ('suite' == key) continue; - if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; - if (key) buf += Array(level).join(' ') + link; - buf += stringifyTOC(obj[key], level); - } - --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 += '' + '\n'; - buf += title(suite.title) + '\n'; - }); - - runner.on('suite end', function(suite){ - --level; - }); - - runner.on('pass', function(test){ - var code = utils.clean(test.fn.toString()); - buf += test.title + '.\n'; - buf += '\n```js'; - 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); - }); -} -}); // module: reporters/markdown.js - -require.register("reporters/min.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `Min`. - */ - -exports = module.exports = Min; - -/** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @param {Runner} runner - * @api public - */ - -function Min(runner) { - Base.call(this, runner); - - runner.on('start', function(){ - // clear screen - process.stdout.write('\033[2J'); - // set cursor position - process.stdout.write('\033[1;3H'); - }); - - runner.on('end', this.epilogue.bind(this)); -} - -/** - * Inherit from `Base.prototype`. - */ - -Min.prototype = new Base; -Min.prototype.constructor = Min; - -}); // module: reporters/min.js - -require.register("reporters/progress.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Progress`. - */ - -exports = module.exports = Progress; - -/** - * General progress bar color. - */ - -Base.colors.progress = 90; - -/** - * Initialize a new `Progress` bar test reporter. - * - * @param {Runner} runner - * @param {Object} options - * @api public - */ - -function Progress(runner, options) { - Base.call(this, runner); - - var self = this - , options = options || {} - , stats = this.stats - , width = Base.window.width * .50 | 0 - , total = runner.total - , complete = 0 - , max = Math.max; - - // default chars - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || '⋅'; - 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 incomplete = total - complete - , percent = complete / total - , n = width * percent | 0 - , i = width - n; - - cursor.CR(); - process.stdout.write('\033[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`. - */ - -Progress.prototype = new Base; -Progress.prototype.constructor = Progress; - - -}); // module: reporters/progress.js - -require.register("reporters/spec.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Spec`. - */ - -exports = module.exports = Spec; - -/** - * Initialize a new `Spec` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Spec(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , indents = 0 - , 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(suite){ - --indents; - if (1 == indents) console.log(); - }); - - runner.on('test', function(test){ - process.stdout.write(indent() + color('pass', ' ◦ ' + test.title + ': ')); - }); - - runner.on('pending', function(test){ - var fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', function(test){ - if ('fast' == test.speed) { - var fmt = indent() - + color('checkmark', ' ✓') - + color('pass', ' %s '); - cursor.CR(); - console.log(fmt, test.title); - } else { - var fmt = indent() - + color('checkmark', ' ✓') - + color('pass', ' %s ') - + color(test.speed, '(%dms)'); - cursor.CR(); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -Spec.prototype = new Base; -Spec.prototype.constructor = Spec; - - -}); // module: reporters/spec.js - -require.register("reporters/tap.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `TAP`. - */ - -exports = module.exports = TAP; - -/** - * Initialize a new `TAP` reporter. - * - * @param {Runner} runner - * @api public - */ - -function TAP(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , n = 1; - - runner.on('start', function(){ - 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){ - console.log('ok %d %s', n, title(test)); - }); - - runner.on('fail', function(test, err){ - console.log('not ok %d %s', n, title(test)); - console.log(err.stack.replace(/^/gm, ' ')); - }); -} - -/** - * Return a TAP-safe title of `test` - * - * @param {Object} test - * @return {String} - * @api private - */ - -function title(test) { - return test.fullTitle().replace(/#/g, ''); -} - -}); // module: reporters/tap.js - -require.register("reporters/teamcity.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `Teamcity`. - */ - -exports = module.exports = Teamcity; - -/** - * Initialize a new `Teamcity` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Teamcity(runner) { - Base.call(this, runner); - var stats = this.stats; - - runner.on('start', function() { - console.log("##teamcity[testSuiteStarted name='mocha.suite']"); - }); - - runner.on('test', function(test) { - console.log("##teamcity[testStarted name='" + escape(test.fullTitle()) + "']"); - }); - - runner.on('fail', function(test, err) { - console.log("##teamcity[testFailed name='" + escape(test.fullTitle()) + "' message='" + escape(err.message) + "']"); - }); - - runner.on('pending', function(test) { - console.log("##teamcity[testIgnored name='" + escape(test.fullTitle()) + "' message='pending']"); - }); - - runner.on('test end', function(test) { - console.log("##teamcity[testFinished name='" + escape(test.fullTitle()) + "' duration='" + test.duration + "']"); - }); - - runner.on('end', function() { - console.log("##teamcity[testSuiteFinished name='mocha.suite' duration='" + stats.duration + "']"); - }); -} - -/** - * Escape the given `str`. - */ - -function escape(str) { - return str - .replace(/\|/g, "||") - .replace(/\n/g, "|n") - .replace(/\r/g, "|r") - .replace(/\[/g, "|[") - .replace(/\]/g, "|]") - .replace(/\u0085/g, "|x") - .replace(/\u2028/g, "|l") - .replace(/\u2029/g, "|p") - .replace(/'/g, "|'"); -} - -}); // module: reporters/teamcity.js - -require.register("reporters/xunit.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `XUnit`. - */ - -exports = module.exports = XUnit; - -/** - * Initialize a new `XUnit` reporter. - * - * @param {Runner} runner - * @api public - */ - -function XUnit(runner) { - Base.call(this, runner); - var stats = this.stats - , tests = [] - , self = this; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('end', function(){ - console.log(tag('testsuite', { - name: 'Mocha Tests' - , tests: stats.tests - , failures: stats.failures - , errors: stats.failures - , skip: stats.tests - stats.failures - stats.passes - , timestamp: (new Date).toUTCString() - , time: stats.duration / 1000 - }, false)); - - tests.forEach(test); - console.log(''); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -XUnit.prototype = new Base; -XUnit.prototype.constructor = XUnit; - - -/** - * Output tag for the given `test.` - */ - -function test(test) { - var attrs = { - classname: test.parent.fullTitle() - , name: test.title - , time: test.duration / 1000 - }; - - if ('failed' == test.state) { - var err = test.err; - attrs.message = escape(err.message); - console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); - } else if (test.pending) { - console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - console.log(tag('testcase', attrs, true) ); - } -} - -/** - * HTML tag helper. - */ - -function tag(name, attrs, close, content) { - var end = close ? '/>' : '>' - , pairs = [] - , tag; - - for (var key in attrs) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) tag += content + ''; -} - -}); // module: reporters/xunit.js - -require.register("runnable.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('runnable'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `Runnable`. - */ - -module.exports = Runnable; - -/** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Runnable(title, fn) { - this.title = title; - this.fn = fn; - this.async = fn && fn.length; - this.sync = ! this.async; - this._timeout = 2000; - this.timedOut = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Runnable.prototype = new EventEmitter; -Runnable.prototype.constructor = Runnable; - - -/** - * Set & get timeout `ms`. - * - * @param {Number} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) this.resetTimeout(); - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Runnable.prototype.fullTitle = function(){ - return this.parent.fullTitle() + ' ' + this.title; -}; - -/** - * Clear the timeout. - * - * @api private - */ - -Runnable.prototype.clearTimeout = function(){ - clearTimeout(this.timer); -}; - -/** - * Reset the timeout. - * - * @api private - */ - -Runnable.prototype.resetTimeout = function(){ - var self = this - , ms = this.timeout(); - - this.clearTimeout(); - if (ms) { - this.timer = setTimeout(function(){ - self.callback(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); - } -}; - -/** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runnable.prototype.run = function(fn){ - var self = this - , ms = this.timeout() - , start = new Date - , ctx = this.ctx - , finished - , emitted; - - if (ctx) ctx.runnable(this); - - // timeout - if (this.async) { - if (ms) { - this.timer = setTimeout(function(){ - done(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); - } - } - - // called multiple times - function multiple() { - if (emitted) return; - emitted = true; - self.emit('error', new Error('done() called multiple times')); - } - - // finished - function done(err) { - if (self.timedOut) return; - if (finished) return multiple(); - self.clearTimeout(); - self.duration = new Date - start; - finished = true; - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // async - if (this.async) { - try { - this.fn.call(ctx, function(err){ - if (err instanceof Error) return done(err); - if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); - done(); - }); - } catch (err) { - done(err); - } - return; - } - - // sync - try { - if (!this.pending) this.fn.call(ctx); - this.duration = new Date - start; - fn(); - } catch (err) { - fn(err); - } -}; - -}); // module: runnable.js - -require.register("runner.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('runner') - , Test = require('./test') - , utils = require('./utils') - , filter = utils.filter - , keys = utils.keys - , noop = function(){}; - -/** - * 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 - * - * @api public - */ - -function Runner(suite) { - var self = this; - this._globals = []; - this.suite = suite; - 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.grep(/.*/); - this.globals(utils.keys(global).concat(['errno'])); -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Runner.prototype = new EventEmitter; -Runner.prototype.constructor = Runner; - - -/** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.grep = function(re){ - debug('grep %s', re); - this._grep = re; - 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 - */ - -Runner.prototype.grepTotal = function(suite) { - var self = this; - var total = 0; - - suite.eachTest(function(test){ - if (self._grep.test(test.fullTitle())) total++; - }); - - return total; -}; - -/** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.globals = function(arr){ - if (0 == arguments.length) return this._globals; - debug('globals %j', arr); - utils.forEach(arr, function(arr){ - this._globals.push(arr); - }, this); - return this; -}; - -/** - * Check for global variable leaks. - * - * @api private - */ - -Runner.prototype.checkGlobals = function(test){ - if (this.ignoreLeaks) return; - var leaks = filterLeaks(this._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`. - * - * @param {Test} test - * @param {Error} err - * @api private - */ - -Runner.prototype.fail = function(test, err){ - ++this.failures; - test.state = 'failed'; - if ('string' == typeof err) { - err = new Error('the string "' + err + '" was thrown, throw an Error :)'); - } - this.emit('fail', test, err); -}; - -/** - * Fail the given `hook` with `err`. - * - * Hook failures (currently) hard-end due - * to that fact that a failing hook will - * surely cause subsequent tests to fail, - * causing jumbled reporting. - * - * @param {Hook} hook - * @param {Error} err - * @api private - */ - -Runner.prototype.failHook = function(hook, err){ - this.fail(hook, err); - this.emit('end'); -}; - -/** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @param {String} name - * @param {Function} function - * @api private - */ - -Runner.prototype.hook = function(name, fn){ - var suite = this.suite - , hooks = suite['_' + name] - , ms = suite._timeout - , self = this - , timer; - - function next(i) { - var hook = hooks[i]; - if (!hook) return fn(); - self.currentRunnable = hook; - - self.emit('hook', hook); - - hook.on('error', function(err){ - self.failHook(hook, err); - }); - - hook.run(function(err){ - hook.removeAllListeners('error'); - if (err) return self.failHook(hook, err); - self.emit('hook end', hook); - next(++i); - }); - } - - process.nextTick(function(){ - next(0); - }); -}; - -/** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err)`. - * - * @param {String} name - * @param {Array} suites - * @param {Function} fn - * @api private - */ - -Runner.prototype.hooks = function(name, suites, fn){ - var self = this - , orig = this.suite; - - function next(suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function(err){ - if (err) { - self.suite = orig; - return fn(err); - } - - 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 - , suites = []; - while (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 test = this.test - , self = this; - - 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. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTests = function(suite, fn){ - var self = this - , tests = suite.tests - , test; - - function next(err) { - // if we bail after first err - if (self.failures && suite._bail) return fn(); - - // next test - test = tests.shift(); - - // all done - if (!test) return fn(); - - // grep - if (!self._grep.test(test.fullTitle())) return next(); - - // pending - if (test.pending) { - 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(){ - self.currentRunnable = self.test; - self.runTest(function(err){ - test = self.test; - - if (err) { - self.fail(test, err); - self.emit('test end', test); - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - next(); -}; - -/** - * Run the given `suite` and invoke the - * callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runSuite = function(suite, fn){ - var total = this.grepTotal(suite) - , self = this - , i = 0; - - debug('run suite %s', suite.fullTitle()); - - if (!total) return fn(); - - this.emit('suite', this.suite = suite); - - function next() { - var curr = suite.suites[i++]; - if (!curr) return done(); - self.runSuite(curr, next); - } - - function done() { - self.suite = suite; - self.hook('afterAll', function(){ - self.emit('suite end', suite); - fn(); - }); - } - - this.hook('beforeAll', function(){ - self.runTests(suite, next); - }); -}; - -/** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ - -Runner.prototype.uncaught = function(err){ - debug('uncaught exception'); - var runnable = this.currentRunnable; - if ('failed' == runnable.state) return; - runnable.clearTimeout(); - err.uncaught = true; - this.fail(runnable, err); - - // recover from test - if ('test' == runnable.type) { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // bail on hooks - this.emit('end'); -}; - -/** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.run = function(fn){ - var self = this - , fn = fn || function(){}; - - debug('start'); - - // callback - this.on('end', function(){ - debug('end'); - process.removeListener('uncaughtException', this.uncaught); - fn(self.failures); - }); - - // run suites - this.emit('start'); - this.runSuite(this.suite, function(){ - debug('finished running'); - self.emit('end'); - }); - - // uncaught exception - process.on('uncaughtException', function(err){ - self.uncaught(err); - }); - - return this; -}; - -/** - * Filter leaks with the given globals flagged as `ok`. - * - * @param {Array} ok - * @return {Array} - * @api private - */ - -function filterLeaks(ok) { - return filter(keys(global), function(key){ - var matched = filter(ok, function(ok){ - return 0 == key.indexOf(ok.split('*')[0]); - }); - return matched.length == 0 && (!global.navigator || 'onerror' !== key); - }); -} -}); // module: runner.js - -require.register("suite.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('suite') - , utils = require('./utils') - , Hook = require('./hook'); - -/** - * 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. - * - * @param {Suite} parent - * @param {String} title - * @return {Suite} - * @api public - */ - -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`. - * - * @param {String} title - * @param {Context} ctx - * @api private - */ - -function Suite(title, ctx) { - this.title = title; - this.ctx = ctx; - this.suites = []; - this.tests = []; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._bail = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Suite.prototype = new EventEmitter; -Suite.prototype.constructor = Suite; - - -/** - * Return a clone of this `Suite`. - * - * @return {Suite} - * @api private - */ - -Suite.prototype.clone = function(){ - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.bail(this.bail()); - return suite; -}; - -/** - * Set timeout `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if (String(ms).match(/s$/)) ms = parseFloat(ms) * 1000; - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; -}; - -/** - * Sets whether to bail after first error. - * - * @parma {Boolean} bail - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.bail = function(bail){ - if (0 == arguments.length) return this._bail; - debug('bail %s', bail); - this._bail = bail; - return this; -}; - -/** - * Run `fn(test[, done])` before running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeAll = function(fn){ - var hook = new Hook('"before all" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterAll = function(fn){ - var hook = new Hook('"after all" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` before each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeEach = function(fn){ - var hook = new Hook('"before each" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterEach = function(fn){ - var hook = new Hook('"after each" hook', fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; -}; - -/** - * Add a test `suite`. - * - * @param {Suite} suite - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addSuite = function(suite){ - suite.parent = this; - suite.timeout(this.timeout()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; -}; - -/** - * Add a `test` to this suite. - * - * @param {Test} test - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addTest = function(test){ - test.parent = this; - test.timeout(this.timeout()); - 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. - * - * @return {String} - * @api public - */ - -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. - * - * @return {Number} - * @api public - */ - -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)`. - * - * @param {Function} fn - * @return {Suite} - * @api private - */ - -Suite.prototype.eachTest = function(fn){ - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite){ - suite.eachTest(fn); - }); - return this; -}; - -}); // module: suite.js - -require.register("test.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Test`. - */ - -module.exports = Test; - -/** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Test(title, fn) { - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -Test.prototype = new Runnable; -Test.prototype.constructor = Test; - - -/** - * Inspect the context void of private properties. - * - * @return {String} - * @api private - */ - -Test.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - return '_' == key[0] - ? undefined - : 'parent' == key - ? '#' - : val; - }, 2); -}; -}); // module: test.js - -require.register("utils.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var fs = require('browser/fs') - , path = require('browser/path') - , join = path.join - , debug = require('browser/debug')('watch'); - -/** - * Ignored directories. - */ - -var ignore = ['node_modules', '.git']; - -/** - * Escape special characters in the given string of html. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html) { - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); -}; - -/** - * Array#forEach (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.forEach = function(arr, fn, scope) { - for (var i = 0, l = arr.length; i < l; i++) - fn.call(scope, arr[i], i); -}; - -/** - * Array#indexOf (<=IE8) - * - * @parma {Array} arr - * @param {Object} obj to find index of - * @param {Number} start - * @api private - */ - -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) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} initial value - * @param {Object} scope - * @api private - */ - -exports.reduce = function(arr, fn, val, scope) { - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn.call(scope, rval, arr[i], i, arr); - } - - return rval; -}; - -/** - * Array#filter (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.filter = function(arr, fn, scope) { - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn.call(scope, val, i, arr)) - ret.push(val); - } - - return ret; -}; - -/** - * Object.keys (<=IE8) - * - * @param {Object} obj - * @return {Array} keys - * @api private - */ - -exports.keys = Object.keys || function(obj) { - var keys = [] - , 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. - * - * @param {Array} files - * @param {Function} fn - * @api private - */ - -exports.watch = function(files, fn){ - var options = { interval: 100 }; - files.forEach(function(file){ - debug('file %s', file); - fs.watchFile(file, options, function(curr, prev){ - if (prev.mtime < curr.mtime) fn(file); - }); - }); -}; - -/** - * Ignored files. - */ - -function ignored(path){ - return !~ignore.indexOf(path); -} - -/** - * Lookup files in the given `dir`. - * - * @return {Array} - * @api private - */ - -exports.files = function(dir, ret){ - ret = ret || []; - - fs.readdirSync(dir) - .filter(ignored) - .forEach(function(path){ - path = join(dir, path); - if (fs.statSync(path).isDirectory()) { - exports.files(path, ret); - } else if (path.match(/\.(js|coffee)$/)) { - ret.push(path); - } - }); - - return ret; -}; - -/** - * Compute a slug from the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.slug = function(str){ - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); -}; - -/** - * Strip the function definition from `str`, - * and re-indent for pre whitespace. - */ - -exports.clean = function(str) { - str = str - .replace(/^function *\(.*\) *{/, '') - .replace(/\s+\}$/, ''); - - var spaces = str.match(/^\n?( *)/)[1].length - , re = new RegExp('^ {' + spaces + '}', 'gm'); - - str = str.replace(re, ''); - - return str.trim(); -}; - -/** - * Escape regular expression characters in `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.escapeRegexp = function(str){ - return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); -}; -}); // module: utils.js diff --git a/coverage.html b/coverage.html deleted file mode 100644 index 16ad6474c4..0000000000 --- a/coverage.html +++ /dev/null @@ -1,333 +0,0 @@ -Coverage

    Coverage

    89%
    772
    694
    78

    connect.js

    100%
    22
    22
    0
    LineHitsSource
    1
    2/*!
    3 * Connect
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var EventEmitter = require('events').EventEmitter
    14 , proto = require('./proto')
    15 , utils = require('./utils')
    16 , path = require('path')
    17 , basename = path.basename
    18 , fs = require('fs');
    19
    20// node patches
    21
    221require('./patch');
    23
    24// expose createServer() as the module
    25
    261exports = module.exports = createServer;
    27
    28/**
    29 * Framework version.
    30 */
    31
    321exports.version = '2.0.0alpha1';
    33
    34/**
    35 * Expose the prototype.
    36 */
    37
    381exports.proto = proto;
    39
    40/**
    41 * Auto-load middleware getters.
    42 */
    43
    441exports.middleware = {};
    45
    46/**
    47 * Expose utilities.
    48 */
    49
    501exports.utils = utils;
    51
    52/**
    53 * Create a new connect server.
    54 *
    55 * @return {Function}
    56 * @api public
    57 */
    58
    591function createServer() {
    60199 function app(req, res){ app.handle(req, res); }
    6171 utils.merge(app, proto);
    6271 utils.merge(app, EventEmitter.prototype);
    6371 app.route = '/';
    6471 app.stack = [];
    6571 return app;
    661};
    67
    68/**
    69 * Auto-load bundled middleware with getters.
    70 */
    71
    721fs.readdirSync(__dirname + '/middleware').forEach(function(filename){
    7323 if (!/\.js$/.test(filename)) return;
    7421 var name = basename(filename, '.js');
    7521 function load(){
    7699 return require('./middleware/' + name);
    77 }
    7821 exports.middleware.__defineGetter__(name, load);
    7921 exports.__defineGetter__(name, load);
    80});

    proto.js

    98%
    62
    61
    1
    LineHitsSource
    1
    2/*!
    3 * Connect - HTTPServer
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var http = require('http')
    14 , parse = require('url').parse
    15 , utils = require('./utils');
    16
    17// prototype
    18
    191var app = module.exports = {};
    20
    21// environment
    22
    231var env = process.env.NODE_ENV || 'development';
    24
    25/**
    26 * Utilize the given middleware `handle` to the given `route`,
    27 * defaulting to _/_. This "route" is the mount-point for the
    28 * middleware, when given a value other than _/_ the middleware
    29 * is only effective when that segment is present in the request's
    30 * pathname.
    31 *
    32 * For example if we were to mount a function at _/admin_, it would
    33 * be invoked on _/admin_, and _/admin/settings_, however it would
    34 * not be invoked for _/_, or _/posts_.
    35 *
    36 * Examples:
    37 *
    38 * var app = connect();
    39 * app.use(connect.favicon());
    40 * app.use(connect.logger());
    41 * app.use(connect.static(__dirname + '/public'));
    42 *
    43 * If we wanted to prefix static files with _/public_, we could
    44 * "mount" the `static()` middleware:
    45 *
    46 * app.use('/public', connect.static(__dirname + '/public'));
    47 *
    48 * This api is chainable, so the following is valid:
    49 *
    50 * connect
    51 * .use(connect.favicon())
    52 * .use(connect.logger())
    53 * .use(connect.static(__dirname + '/public'))
    54 * .listen(3000);
    55 *
    56 * @param {String|Function|Server} route, callback or server
    57 * @param {Function|Server} callback or server
    58 * @return {Server} for chaining
    59 * @api public
    60 */
    61
    621app.use = function(route, fn){
    63 // default route to '/'
    64155 if ('string' != typeof route) {
    65150 fn = route;
    66150 route = '/';
    67 }
    68
    69 // wrap sub-apps
    70155 if ('function' == typeof fn.handle) {
    714 var server = fn;
    724 fn.route = route;
    734 fn = function(req, res, next){
    742 server.handle(req, res, next);
    75 };
    76 }
    77
    78 // wrap vanilla http.Servers
    79155 if (fn instanceof http.Server) {
    801 fn = fn.listeners('request')[0];
    81 }
    82
    83 // strip trailing slash
    84155 if ('/' == route[route.length - 1]) {
    85151 route = route.slice(0, -1);
    86 }
    87
    88 // add the middleware
    89155 this.stack.push({ route: route, handle: fn });
    90
    91155 return this;
    92};
    93
    94/**
    95 * Handle server requests, punting them down
    96 * the middleware stack.
    97 *
    98 * @api private
    99 */
    100
    1011app.handle = function(req, res, out) {
    102130 var stack = this.stack
    103 , fqdn = ~req.url.indexOf('://')
    104 , removed = ''
    105 , index = 0;
    106
    107130 function next(err) {
    108268 var layer, path, status, c;
    109268 req.url = removed + req.url;
    110268 req.originalUrl = req.originalUrl || req.url;
    111268 removed = '';
    112
    113 // next callback
    114268 layer = stack[index++];
    115
    116 // all done
    117268 if (!layer || res.headerSent) {
    118 // delegate to parent
    11911 if (out) return out(err);
    120
    121 // unhandled error
    12211 if (err) {
    123 // default to 500
    12416 if (res.statusCode < 400) res.statusCode = 500;
    125
    126 // respect err.status
    12714 if (err.status) res.statusCode = err.status;
    128
    129 // production gets a basic error message
    1308 var msg = 'production' == env
    131 ? http.STATUS_CODES[res.statusCode]
    132 : err.stack || err.toString();
    133
    134 // log to stderr in a non-test env
    1358 if ('test' != env) console.error(err.stack || err.toString());
    1368 if (res.headerSent) return req.socket.destroy();
    1378 res.setHeader('Content-Type', 'text/plain');
    1388 res.setHeader('Content-Length', Buffer.byteLength(msg));
    1398 if ('HEAD' == req.method) return res.end();
    1408 res.end(msg);
    141 } else {
    1423 res.statusCode = 404;
    1433 res.setHeader('Content-Type', 'text/plain');
    1443 if ('HEAD' == req.method) return res.end();
    1453 res.end('Cannot ' + req.method + ' ' + utils.escape(req.url));
    146 }
    14711 return;
    148 }
    149
    150257 try {
    151257 path = parse(req.url).pathname;
    152257 if (undefined == path) path = '/';
    153
    154 // skip this layer if the route doesn't match.
    155257 if (0 != path.indexOf(layer.route)) return next(err);
    156
    157257 c = path[layer.route.length];
    158257 if (c && '/' != c && '.' != c) return next(err);
    159
    160 // Call the layer handler
    161 // Trim off the part of the url that matches the route
    162257 removed = layer.route;
    163257 req.url = req.url.substr(removed.length);
    164
    165 // Ensure leading slash
    166260 if (!fqdn && '/' != req.url[0]) req.url = '/' + req.url;
    167
    168257 var arity = layer.handle.length;
    169257 if (err) {
    1708 if (arity === 4) {
    1713 layer.handle(err, req, res, next);
    172 } else {
    1735 next(err);
    174 }
    175249 } else if (arity < 4) {
    176249 layer.handle(req, res, next);
    177 } else {
    1780 next();
    179 }
    180 } catch (e) {
    1811 next(e);
    182 }
    183 }
    184130 next();
    185};

    utils.js

    86%
    129
    111
    18
    LineHitsSource
    1
    2/*!
    3 * Connect - utils
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var http = require('http')
    14 , crypto = require('crypto')
    15 , Path = require('path')
    16 , fs = require('fs');
    17
    18/**
    19 * Extract the mime type from the given request's
    20 * _Content-Type_ header.
    21 *
    22 * @param {IncomingMessage} req
    23 * @return {String}
    24 * @api private
    25 */
    26
    271exports.mime = function(req) {
    2849 var str = req.headers['content-type'] || '';
    2949 return str.split(';')[0];
    30};
    31
    32/**
    33 * Generate an `Error` from the given status `code`.
    34 *
    35 * @param {Number} code
    36 * @return {Error}
    37 * @api private
    38 */
    39
    401exports.error = function(code){
    415 var err = new Error(http.STATUS_CODES[code]);
    425 err.status = code;
    435 return err;
    44};
    45
    46/**
    47 * Flatten the given `arr`.
    48 *
    49 * @param {Array} arr
    50 * @return {Array}
    51 * @api private
    52 */
    53
    541exports.flatten = function(arr, ret){
    550 var ret = ret || []
    56 , len = arr.length;
    570 for (var i = 0; i < len; ++i) {
    580 if (Array.isArray(arr[i])) {
    590 exports.flatten(arr[i], ret);
    60 } else {
    610 ret.push(arr[i]);
    62 }
    63 }
    640 return ret;
    65};
    66
    67/**
    68 * Return md5 hash of the given string and optional encoding,
    69 * defaulting to hex.
    70 *
    71 * utils.md5('wahoo');
    72 * // => "e493298061761236c96b02ea6aa8a2ad"
    73 *
    74 * @param {String} str
    75 * @param {String} encoding
    76 * @return {String}
    77 * @api public
    78 */
    79
    801exports.md5 = function(str, encoding){
    810 return crypto
    82 .createHash('md5')
    83 .update(str)
    84 .digest(encoding || 'hex');
    85};
    86
    87/**
    88 * Merge object b with object a.
    89 *
    90 * var a = { foo: 'bar' }
    91 * , b = { bar: 'baz' };
    92 *
    93 * utils.merge(a, b);
    94 * // => { foo: 'bar', bar: 'baz' }
    95 *
    96 * @param {Object} a
    97 * @param {Object} b
    98 * @return {Object}
    99 * @api private
    100 */
    101
    1021exports.merge = function(a, b){
    103178 if (a && b) {
    104178 for (var key in b) {
    105885 a[key] = b[key];
    106 }
    107 }
    108178 return a;
    109};
    110
    111/**
    112 * Escape the given string of `html`.
    113 *
    114 * @param {String} html
    115 * @return {String}
    116 * @api private
    117 */
    118
    1191exports.escape = function(html){
    1203 return String(html)
    121 .replace(/&(?!\w+;)/g, '&amp;')
    122 .replace(/</g, '&lt;')
    123 .replace(/>/g, '&gt;')
    124 .replace(/"/g, '&quot;');
    125};
    126
    127
    128/**
    129 * Return a unique identifier with the given `len`.
    130 *
    131 * utils.uid(10);
    132 * // => "FDaS435D2z"
    133 *
    134 * @param {Number} len
    135 * @return {String}
    136 * @api private
    137 */
    138
    1391exports.uid = function(len) {
    14043 return crypto.randomBytes(Math.ceil(len * 3 / 4))
    141 .toString('base64')
    142 .slice(0, len);
    143};
    144
    145/**
    146 * Sign the given `val` with `secret`.
    147 *
    148 * @param {String} val
    149 * @param {String} secret
    150 * @return {String}
    151 * @api private
    152 */
    153
    1541exports.sign = function(val, secret){
    15547 return val + '.' + crypto
    156 .createHmac('sha1', secret)
    157 .update(val)
    158 .digest('base64')
    159 .replace(/=+$/, '');
    160};
    161
    162/**
    163 * Unsign and decode the given `val` with `secret`,
    164 * returning `false` if the signature is invalid.
    165 *
    166 * @param {String} val
    167 * @param {String} secret
    168 * @return {String|Boolean}
    169 * @api private
    170 */
    171
    1721exports.unsign = function(val, secret){
    17317 var str = val.slice(0,val.lastIndexOf('.'));
    17417 return exports.sign(str, secret) == val
    175 ? str
    176 : false;
    177};
    178
    179/**
    180 * Parse signed cookies, returning an object
    181 * containing the decoded key/value pairs,
    182 * while removing the signed key from `obj`.
    183 *
    184 * @param {Object} obj
    185 * @return {Object}
    186 * @api private
    187 */
    188
    1891exports.parseSignedCookies = function(obj, secret){
    1908 var ret = {};
    1918 Object.keys(obj).forEach(function(key){
    19212 var val = obj[key]
    193 , signed = exports.unsign(val, secret);
    194
    19512 if (signed) {
    1967 ret[key] = signed;
    1977 delete obj[key];
    198 }
    199 });
    2008 return ret;
    201};
    202
    203/**
    204 * Parse JSON cookies.
    205 *
    206 * @param {Object} obj
    207 * @return {Object}
    208 * @api private
    209 */
    210
    2111exports.parseJSONCookies = function(obj){
    21216 Object.keys(obj).forEach(function(key){
    21312 var val = obj[key];
    21412 if (0 == val.indexOf('j:')) {
    2152 try {
    2162 obj[key] = JSON.parse(val.slice(2));
    217 } catch (err) {
    218 // nothing
    219 }
    220 }
    221 });
    22216 return obj;
    223};
    224
    225/**
    226 * Parse the given cookie string into an object.
    227 *
    228 * @param {String} str
    229 * @return {Object}
    230 * @api private
    231 */
    232
    2331exports.parseCookie = function(str){
    23414 var obj = {}
    235 , pairs = str.split(/[;,] */);
    23614 for (var i = 0, len = pairs.length; i < len; ++i) {
    23719 var pair = pairs[i]
    238 , eqlIndex = pair.indexOf('=')
    239 , key = pair.substr(0, eqlIndex).trim()
    240 , val = pair.substr(++eqlIndex, pair.length).trim();
    241
    242 // quoted values
    24320 if ('"' == val[0]) val = val.slice(1, -1);
    244
    245 // only assign once
    24619 if (undefined == obj[key]) {
    24719 val = val.replace(/\+/g, ' ');
    24819 try {
    24919 obj[key] = decodeURIComponent(val);
    250 } catch (err) {
    2510 if (err instanceof URIError) {
    2520 obj[key] = val;
    253 } else {
    2540 throw err;
    255 }
    256 }
    257 }
    258 }
    25914 return obj;
    260};
    261
    262/**
    263 * Serialize the given object into a cookie string.
    264 *
    265 * utils.serializeCookie('name', 'tj', { httpOnly: true })
    266 * // => "name=tj; httpOnly"
    267 *
    268 * @param {String} name
    269 * @param {String} val
    270 * @param {Object} obj
    271 * @return {String}
    272 * @api private
    273 */
    274
    2751exports.serializeCookie = function(name, val, obj){
    27633 var pairs = [name + '=' + encodeURIComponent(val)]
    277 , obj = obj || {};
    278
    27933 if (obj.domain) pairs.push('domain=' + obj.domain);
    28062 if (obj.path) pairs.push('path=' + obj.path);
    28150 if (obj.expires) pairs.push('expires=' + obj.expires.toUTCString());
    28257 if (obj.httpOnly) pairs.push('httpOnly');
    28337 if (obj.secure) pairs.push('secure');
    284
    28533 return pairs.join('; ');
    286};
    287
    288/**
    289 * Pause `data` and `end` events on the given `obj`.
    290 * Middleware performing async tasks _should_ utilize
    291 * this utility (or similar), to re-emit data once
    292 * the async operation has completed, otherwise these
    293 * events may be lost.
    294 *
    295 * var pause = utils.pause(req);
    296 * fs.readFile(path, function(){
    297 * next();
    298 * pause.resume();
    299 * });
    300 *
    301 * @param {Object} obj
    302 * @return {Object}
    303 * @api private
    304 */
    305
    3061exports.pause = function(obj){
    3077 var onData
    308 , onEnd
    309 , events = [];
    310
    311 // buffer data
    3127 obj.on('data', onData = function(data, encoding){
    3130 events.push(['data', data, encoding]);
    314 });
    315
    316 // buffer end
    3177 obj.on('end', onEnd = function(data, encoding){
    3186 events.push(['end', data, encoding]);
    319 });
    320
    3217 return {
    322 end: function(){
    3236 obj.removeListener('data', onData);
    3246 obj.removeListener('end', onEnd);
    325 },
    326 resume: function(){
    3276 this.end();
    3286 for (var i = 0, len = events.length; i < len; ++i) {
    3295 obj.emit.apply(obj, events[i]);
    330 }
    331 }
    332 };
    333};
    334
    335/**
    336 * Check `req` and `res` to see if it has been modified.
    337 *
    338 * @param {IncomingMessage} req
    339 * @param {ServerResponse} res
    340 * @return {Boolean}
    341 * @api private
    342 */
    343
    3441exports.modified = function(req, res, headers) {
    3451 var headers = headers || res._headers || {}
    346 , modifiedSince = req.headers['if-modified-since']
    347 , lastModified = headers['last-modified']
    348 , noneMatch = req.headers['if-none-match']
    349 , etag = headers['etag'];
    350
    3511 if (noneMatch) noneMatch = noneMatch.split(/ *, */);
    352
    353 // check If-None-Match
    3541 if (noneMatch && etag && ~noneMatch.indexOf(etag)) {
    3550 return false;
    356 }
    357
    358 // check If-Modified-Since
    3591 if (modifiedSince && lastModified) {
    3601 modifiedSince = new Date(modifiedSince);
    3611 lastModified = new Date(lastModified);
    362 // Ignore invalid dates
    3631 if (!isNaN(modifiedSince.getTime())) {
    3642 if (lastModified <= modifiedSince) return false;
    365 }
    366 }
    367
    3680 return true;
    369};
    370
    371/**
    372 * Strip `Content-*` headers from `res`.
    373 *
    374 * @param {ServerResponse} res
    375 * @api private
    376 */
    377
    3781exports.removeContentHeaders = function(res){
    3791 Object.keys(res._headers).forEach(function(field){
    3806 if (0 == field.indexOf('content')) {
    3811 res.removeHeader(field);
    382 }
    383 });
    384};
    385
    386/**
    387 * Check if `req` is a conditional GET request.
    388 *
    389 * @param {IncomingMessage} req
    390 * @return {Boolean}
    391 * @api private
    392 */
    393
    3941exports.conditionalGET = function(req) {
    39536 return req.headers['if-modified-since']
    396 || req.headers['if-none-match'];
    397};
    398
    399/**
    400 * Respond with 401 "Unauthorized".
    401 *
    402 * @param {ServerResponse} res
    403 * @param {String} realm
    404 * @api private
    405 */
    406
    4071exports.unauthorized = function(res, realm) {
    4086 res.statusCode = 401;
    4096 res.setHeader('WWW-Authenticate', 'Basic realm="' + realm + '"');
    4106 res.end('Unauthorized');
    411};
    412
    413/**
    414 * Respond with 304 "Not Modified".
    415 *
    416 * @param {ServerResponse} res
    417 * @param {Object} headers
    418 * @api private
    419 */
    420
    4211exports.notModified = function(res) {
    4221 exports.removeContentHeaders(res);
    4231 res.statusCode = 304;
    4241 res.end();
    425};
    426
    427/**
    428 * Return an ETag in the form of `"<size>-<mtime>"`
    429 * from the given `stat`.
    430 *
    431 * @param {Object} stat
    432 * @return {String}
    433 * @api private
    434 */
    435
    4361exports.etag = function(stat) {
    4370 return '"' + stat.size + '-' + Number(stat.mtime) + '"';
    438};
    439
    440/**
    441 * Parse "Range" header `str` relative to the given file `size`.
    442 *
    443 * @param {Number} size
    444 * @param {String} str
    445 * @return {Array}
    446 * @api private
    447 */
    448
    4491exports.parseRange = function(size, str){
    45015 var valid = true;
    45115 var arr = str.substr(6).split(',').map(function(range){
    45215 var range = range.split('-')
    453 , start = parseInt(range[0], 10)
    454 , end = parseInt(range[1], 10);
    455
    456 // -500
    45715 if (isNaN(start)) {
    4584 start = size - end;
    4594 end = size - 1;
    460 // 500-
    46111 } else if (isNaN(end)) {
    4623 end = size - 1;
    463 }
    464
    465 // Invalid
    46616 if (isNaN(start) || isNaN(end) || start > end) valid = false;
    467
    46815 return { start: start, end: end };
    469 });
    47015 return valid ? arr : undefined;
    471};
    472
    473/**
    474 * Parse the given Cache-Control `str`.
    475 *
    476 * @param {String} str
    477 * @return {Object}
    478 * @api private
    479 */
    480
    4811exports.parseCacheControl = function(str){
    48226 var directives = str.split(',')
    483 , obj = {};
    484
    48526 for(var i = 0, len = directives.length; i < len; i++) {
    48637 var parts = directives[i].split('=')
    487 , key = parts.shift().trim()
    488 , val = parseInt(parts.shift(), 10);
    489
    49037 obj[key] = isNaN(val) ? true : val;
    491 }
    492
    49326 return obj;
    494};
    495
    496/**
    497 * Convert array-like object to an `Array`.
    498 *
    499 * node-bench measured "16.5 times faster than Array.prototype.slice.call()"
    500 *
    501 * @param {Object} obj
    502 * @return {Array}
    503 * @api private
    504 */
    505
    5061var toArray = exports.toArray = function(obj){
    5070 var len = obj.length
    508 , arr = new Array(len);
    5090 for (var i = 0; i < len; ++i) {
    5100 arr[i] = obj[i];
    511 }
    5120 return arr;
    513};

    patch.js

    90%
    21
    19
    2
    LineHitsSource
    1
    2/*!
    3 * Connect
    4 * Copyright(c) 2011 TJ Holowaychuk
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Module dependencies.
    10 */
    11
    121var http = require('http')
    13 , res = http.ServerResponse.prototype
    14 , setHeader = res.setHeader
    15 , _renderHeaders = res._renderHeaders
    16 , writeHead = res.writeHead;
    17
    18// apply only once
    19
    201if (!res._hasConnectPatch) {
    21
    22 /**
    23 * Provide a public "header sent" flag
    24 * until node does.
    25 *
    26 * @return {Boolean}
    27 * @api public
    28 */
    29
    301 res.__defineGetter__('headerSent', function(){
    31273 return this._header;
    32 });
    33
    34 /**
    35 * Set header `field` to `val`, special-casing
    36 * the `Set-Cookie` field for multiple support.
    37 *
    38 * @param {String} field
    39 * @param {String} val
    40 * @api public
    41 */
    42
    431 res.setHeader = function(field, val){
    44265 var key = field.toLowerCase()
    45 , prev;
    46
    47 // special-case Set-Cookie
    48265 if (this._headers && 'set-cookie' == key) {
    493 if (prev = this.getHeader(field)) {
    500 val = Array.isArray(prev)
    51 ? prev.concat(val)
    52 : [prev, val];
    53 }
    54 // charset
    55262 } else if ('content-type' == key && this.charset) {
    560 val += '; charset=' + this.charset;
    57 }
    58
    59265 return setHeader.call(this, field, val);
    60 };
    61
    62 /**
    63 * Proxy to emit "header" event.
    64 */
    65
    661 res._renderHeaders = function(){
    6778 if (!this._emittedHeader) this.emit('header');
    6878 this._emittedHeader = true;
    6978 return _renderHeaders.call(this);
    70 };
    71
    721 res.writeHead = function(){
    73256 if (!this._emittedHeader) this.emit('header');
    74128 this._emittedHeader = true;
    75128 return writeHead.apply(this, arguments);
    76 };
    77
    781 res._hasConnectPatch = true;
    79}

    middleware/basicAuth.js

    100%
    28
    28
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - basicAuth
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var utils = require('../utils')
    14 , unauthorized = utils.unauthorized;
    15
    16/**
    17 * Basic Auth:
    18 *
    19 * Enfore basic authentication by providing a `callback(user, pass)`,
    20 * which must return `true` in order to gain access. Alternatively an async
    21 * method is provided as well, invoking `callback(user, pass, callback)`. Populates
    22 * `req.user`. The final alternative is simply passing username / password
    23 * strings.
    24 *
    25 * Simple username and password
    26 *
    27 * connect(connect.basicAuth('username', 'password'));
    28 *
    29 * Callback verification
    30 *
    31 * connect()
    32 * .use(connect.basicAuth(function(user, pass){
    33 * return 'tj' == user & 'wahoo' == pass;
    34 * }))
    35 *
    36 * Async callback verification, accepting `fn(err, user)`.
    37 *
    38 * connect()
    39 * .use(connect.basicAuth(function(user, pass, fn){
    40 * User.authenticate({ user: user, pass: pass }, fn);
    41 * }))
    42 *
    43 * @param {Function|String} callback or username
    44 * @param {String} realm
    45 * @api public
    46 */
    47
    481module.exports = function basicAuth(callback, realm) {
    493 var username, password;
    50
    51 // user / pass strings
    523 if ('string' == typeof callback) {
    531 username = callback;
    541 password = realm;
    551 if ('string' != typeof password) throw new Error('password argument required');
    561 realm = arguments[2];
    571 callback = function(user, pass){
    582 return user == username && pass == password;
    59 }
    60 }
    61
    623 realm = realm || 'Authorization Required';
    63
    643 return function(req, res, next) {
    659 var authorization = req.headers.authorization;
    66
    679 if (req.user) return next();
    6812 if (!authorization) return unauthorized(res, realm);
    69
    706 var parts = authorization.split(' ')
    71 , scheme = parts[0]
    72 , credentials = new Buffer(parts[1], 'base64').toString().split(':')
    73 , user = credentials[0]
    74 , pass = credentials[1];
    75
    766 if ('Basic' != scheme) return next(utils.error(400));
    77
    78 // async
    796 if (callback.length >= 3) {
    802 var pause = utils.pause(req);
    812 callback(user, pass, function(err, user){
    823 if (err || !user) return unauthorized(res, realm);
    831 req.user = user;
    841 next();
    851 pause.resume();
    86 });
    87 // sync
    88 } else {
    894 if (callback(user, pass)) {
    902 req.user = user;
    912 next();
    92 } else {
    932 unauthorized(res, realm);
    94 }
    95 }
    96 }
    97};
    98

    middleware/bodyParser.js

    100%
    9
    9
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - bodyParser
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var multipart = require('./multipart')
    14 , urlencoded = require('./urlencoded')
    15 , json = require('./json');
    16
    17/**
    18 * Body parser:
    19 *
    20 * Parse request bodies, supports _application/json_,
    21 * _application/x-www-form-urlencoded_, and _multipart/form-data_.
    22 *
    23 * This is equivalent to:
    24 *
    25 * app.use(connect.json());
    26 * app.use(connect.urlencoded());
    27 * app.use(connect.multipart());
    28 *
    29 * Examples:
    30 *
    31 * connect()
    32 * .use(connect.bodyParser())
    33 * .use(function(req, res) {
    34 * res.end('viewing user ' + req.body.user.name);
    35 * });
    36 *
    37 * $ curl -d 'user[name]=tj' http://local/
    38 * $ curl -d '{"user":{"name":"tj"}}' -H "Content-Type: application/json" http://local/
    39 *
    40 * View [json](json.html), [urlencoded](urlencoded.html), and [multipart](multipart.html) for more info.
    41 *
    42 * @param {Object} options
    43 * @return {Function}
    44 * @api public
    45 */
    46
    471exports = module.exports = function bodyParser(options){
    486 var _urlencoded = urlencoded(options)
    49 , _multipart = multipart(options)
    50 , _json = json(options);
    51
    526 return function bodyParser(req, res, next) {
    5311 _json(req, res, function(err){
    5411 if (err) return next(err);
    5511 _urlencoded(req, res, function(err){
    5611 if (err) return next(err);
    5711 _multipart(req, res, next);
    58 });
    59 });
    60 }
    61};

    middleware/multipart.js

    94%
    34
    32
    2
    LineHitsSource
    1
    2/*!
    3 * Connect - multipart
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var formidable = require('formidable')
    14 , utils = require('../utils')
    15 , qs = require('qs');
    16
    17/**
    18 * Multipart:
    19 *
    20 * Parse multipart/form-data request bodies,
    21 * providing the parsed object as `req.body`
    22 * and `req.files`.
    23 *
    24 * Configuration:
    25 *
    26 * The options passed are merged with [formidable](https://github.com/felixge/node-formidable)'s
    27 * `IncomingForm` object, allowing you to configure the upload directory,
    28 * size limits, etc. For example if you wish to change the upload dir do the following.
    29 *
    30 * app.use(connect.multipart({ uploadDir: path }));
    31 *
    32 * @param {Object} options
    33 * @return {Function}
    34 * @api public
    35 */
    36
    371exports = module.exports = function(options){
    3813 options = options || {};
    3913 return function multipart(req, res, next) {
    4024 if (req._body) return next();
    4120 req.body = req.body || {};
    4220 req.files = req.files || {};
    43
    44 // ignore GET
    4521 if ('GET' == req.method || 'HEAD' == req.method) return next();
    46
    47 // check Content-Type
    4822 if ('multipart/form-data' != utils.mime(req)) return next();
    49
    50 // flag as parsed
    5116 req._body = true;
    52
    53 // parse
    5416 var form = new formidable.IncomingForm
    55 , data = {}
    56 , files = {}
    57 , done;
    58
    5916 Object.keys(options).forEach(function(key){
    602 form[key] = options[key];
    61 });
    62
    6316 function ondata(name, val, data){
    6432 if (Array.isArray(data[name])) {
    650 data[name].push(val);
    6632 } else if (data[name]) {
    672 data[name] = [data[name], val];
    68 } else {
    6930 data[name] = val;
    70 }
    71 }
    72
    7316 form.on('field', function(name, val){
    7418 ondata(name, val, data);
    75 });
    76
    7716 form.on('file', function(name, val){
    7814 ondata(name, val, files);
    79 });
    80
    8116 form.on('error', function(err){
    822 next(err);
    832 done = true;
    84 });
    85
    8616 form.on('end', function(){
    8718 if (done) return;
    8814 try {
    8914 req.body = qs.parse(data);
    9014 req.files = qs.parse(files);
    9114 next();
    92 } catch (err) {
    930 next(err);
    94 }
    95 });
    96
    9716 form.parse(req);
    98 }
    99};

    middleware/urlencoded.js

    94%
    17
    16
    1
    LineHitsSource
    1
    2/*!
    3 * Connect - urlencoded
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var utils = require('../utils')
    14 , qs = require('qs');
    15
    16/**
    17 * Urlencoded:
    18 *
    19 * Parse x-ww-form-urlencoded request bodies,
    20 * providing the parsed object as `req.body`.
    21 *
    22 * @param {Object} options
    23 * @return {Function}
    24 * @api public
    25 */
    26
    271exports = module.exports = function(options){
    287 options = options || {};
    297 return function urlencoded(req, res, next) {
    3014 if (req._body) return next();
    3112 req.body = req.body || {};
    32
    33 // ignore GET
    3412 if ('GET' == req.method || 'HEAD' == req.method) return next();
    35
    36 // check Content-Type
    3722 if ('application/x-www-form-urlencoded' != utils.mime(req)) return next();
    38
    39 // flag as parsed
    402 req._body = true;
    41
    42 // parse
    432 var buf = '';
    442 req.setEncoding('utf8');
    454 req.on('data', function(chunk){ buf += chunk });
    462 req.on('end', function(){
    472 try {
    482 req.body = buf.length
    49 ? qs.parse(buf)
    50 : {};
    512 next();
    52 } catch (err){
    530 next(err);
    54 }
    55 });
    56 }
    57};

    middleware/json.js

    100%
    18
    18
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - json
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var utils = require('../utils');
    14
    15/**
    16 * JSON:
    17 *
    18 * Parse JSON request bodies, providing the
    19 * parsed object as `req.body`.
    20 *
    21 * @param {Object} options
    22 * @return {Function}
    23 * @api public
    24 */
    25
    261exports = module.exports = function(options){
    278 options = options || {};
    288 return function json(req, res, next) {
    2916 if (req._body) return next();
    3016 req.body = req.body || {};
    31
    32 // ignore GET
    3317 if ('GET' == req.method || 'HEAD' == req.method) return next();
    34
    35 // check Content-Type
    3626 if ('application/json' != utils.mime(req)) return next();
    37
    38 // flag as parsed
    394 req._body = true;
    40
    41 // parse
    424 var buf = '';
    434 req.setEncoding('utf8');
    448 req.on('data', function(chunk){ buf += chunk });
    454 req.on('end', function(){
    464 try {
    474 req.body = buf.length
    48 ? JSON.parse(buf)
    49 : {};
    502 next();
    51 } catch (err){
    522 err.status = 400;
    532 next(err);
    54 }
    55 });
    56 }
    57};

    middleware/compress.js

    100%
    35
    35
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - compress
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var zlib = require('zlib');
    14
    15/**
    16 * Supported content-encoding methods.
    17 */
    18
    191exports.methods = {
    20 gzip: zlib.createGzip
    21 , deflate: zlib.createDeflate
    22};
    23
    24/**
    25 * Default filter function.
    26 */
    27
    281exports.filter = function(req, res){
    299 var type = res.getHeader('Content-Type') || '';
    309 return type.match(/json|text|javascript/);
    31};
    32
    33/**
    34 * Compress:
    35 *
    36 * Compress response data with gzip/deflate.
    37 *
    38 * Filter:
    39 *
    40 * A `filter` callback function may be passed to
    41 * replace the default logic of:
    42 *
    43 * exports.filter = function(req, res){
    44 * var type = res.getHeader('Content-Type') || '';
    45 * return type.match(/json|text|javascript/);
    46 * };
    47 *
    48 * Options:
    49 *
    50 * All remaining options are passed to the gzip/deflate
    51 * creation functions. Consult node's docs for additional details.
    52 *
    53 * - `chunkSize` (default: 16*1024)
    54 * - `windowBits`
    55 * - `level`: 0-9 where 0 is no compression, and 9 is slow but best compression
    56 * - `memLevel`: 1-9 low is slower but uses less memory, high is fast but uses more
    57 * - `strategy`: compression strategy
    58 *
    59 * @param {Object} options
    60 * @return {Function}
    61 * @api public
    62 */
    63
    641module.exports = function compress(options) {
    651 var options = options || {}
    66 , names = Object.keys(exports.methods)
    67 , filter = options.filter || exports.filter;
    68
    691 return function(req, res, next){
    709 var accept = req.headers['accept-encoding']
    71 , write = res.write
    72 , end = res.end
    73 , stream
    74 , method;
    75
    76 // vary
    779 res.setHeader('Vary', 'Accept-Encoding');
    78
    79 // proxy
    80
    819 res.write = function(chunk, encoding){
    8214 if (!this.headerSent) this._implicitHeader();
    837 return stream
    84 ? stream.write(chunk, encoding)
    85 : write.call(res, chunk, encoding);
    86 };
    87
    889 res.end = function(chunk, encoding){
    899 if (chunk) this.write(chunk, encoding);
    909 return stream
    91 ? stream.end()
    92 : end.call(res);
    93 };
    94
    959 res.on('header', function(){
    96 // default request filter
    9710 if (!filter(req, res)) return;
    98
    99 // SHOULD use identity
    1009 if (!accept) return;
    101
    102 // head
    1038 if ('HEAD' == req.method) return;
    104
    105 // default to gzip
    1066 if ('*' == accept.trim()) method = 'gzip';
    107
    108 // compression method
    1096 if (!method) {
    1106 for (var i = 0, len = names.length; i < len; ++i) {
    1116 if (~accept.indexOf(names[i])) {
    1126 method = names[i];
    1136 break;
    114 }
    115 }
    116 }
    117
    118 // compression method
    1196 if (!method) return;
    120
    121 // compression stream
    1226 stream = exports.methods[method](options);
    123
    124 // header fields
    1256 res.setHeader('Content-Encoding', method);
    1266 res.removeHeader('Content-Length');
    127
    128 // compression
    129
    1306 stream.on('data', function(chunk){
    13112 write.call(res, chunk);
    132 });
    133
    1346 stream.on('end', function(){
    1356 end.call(res);
    136 });
    137
    138 });
    139
    1409 next();
    141 };
    142}

    middleware/static.js

    90%
    77
    70
    7
    LineHitsSource
    1/*!
    2 * Connect - staticProvider
    3 * Copyright(c) 2010 Sencha Inc.
    4 * Copyright(c) 2011 TJ Holowaychuk
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Module dependencies.
    10 */
    11
    121var fs = require('fs')
    13 , path = require('path')
    14 , join = path.join
    15 , basename = path.basename
    16 , normalize = path.normalize
    17 , utils = require('../utils')
    18 , Buffer = require('buffer').Buffer
    19 , parse = require('url').parse
    20 , mime = require('mime');
    21
    22/**
    23 * Static:
    24 *
    25 * Static file server with the given `root` path.
    26 *
    27 * Examples:
    28 *
    29 * var oneDay = 86400000;
    30 *
    31 * connect()
    32 * .use(connect.static(__dirname + '/public'))
    33 *
    34 * connect()
    35 * .use(connect.static(__dirname + '/public', { maxAge: oneDay }))
    36 *
    37 * Options:
    38 *
    39 * - `maxAge` Browser cache maxAge in milliseconds. defaults to 0
    40 * - `hidden` Allow transfer of hidden files. defaults to false
    41 * - `redirect` Redirect to trailing "/" when the pathname is a dir
    42 *
    43 * @param {String} root
    44 * @param {Object} options
    45 * @return {Function}
    46 * @api public
    47 */
    48
    491exports = module.exports = function static(root, options){
    506 options = options || {};
    51
    52 // root required
    536 if (!root) throw new Error('static() root path required');
    546 options.root = root;
    55
    566 return function static(req, res, next) {
    5736 options.path = req.url;
    5836 options.getOnly = true;
    5936 send(req, res, next, options);
    60 };
    61};
    62
    63/**
    64 * Expose mime module.
    65 *
    66 * If you wish to extend the mime table use this
    67 * reference to the "mime" module in the npm registry.
    68 */
    69
    701exports.mime = mime;
    71
    72/**
    73 * decodeURIComponent.
    74 *
    75 * Allows V8 to only deoptimize this fn instead of all
    76 * of send().
    77 *
    78 * @param {String} path
    79 * @api private
    80 */
    81
    821function decode(path){
    8336 try {
    8436 return decodeURIComponent(path);
    85 } catch (err) {
    861 return err;
    87 }
    88}
    89
    90/**
    91 * Attempt to tranfer the requested file to `res`.
    92 *
    93 * @param {ServerRequest}
    94 * @param {ServerResponse}
    95 * @param {Function} next
    96 * @param {Object} options
    97 * @api private
    98 */
    99
    1001var send = exports.send = function(req, res, next, options){
    10136 options = options || {};
    10236 if (!options.path) throw new Error('path required');
    103
    104 // setup
    10536 var maxAge = options.maxAge || 0
    106 , ranges = req.headers.range
    107 , head = 'HEAD' == req.method
    108 , get = 'GET' == req.method
    109 , root = options.root ? normalize(options.root) : null
    110 , redirect = false === options.redirect ? false : true
    111 , getOnly = options.getOnly
    112 , fn = options.callback
    113 , hidden = options.hidden
    114 , done;
    115
    116 // replace next() with callback when available
    11736 if (fn) next = fn;
    118
    119 // ignore non-GET requests
    12036 if (getOnly && !get && !head) return next();
    121
    122 // parse url
    12336 var url = parse(options.path)
    124 , path = decode(url.pathname)
    125 , type;
    126
    12737 if ('URIError: URI malformed' == path) return next(utils.error(400));
    128
    129 // null byte(s)
    13035 if (~path.indexOf('\0')) return next(utils.error(400));
    131
    132 // when root is not given, consider .. malicious
    13335 if (!root && ~path.indexOf('..')) return next(utils.error(403));
    134
    135 // index.html support
    13636 if (normalize('/') == path[path.length - 1]) path += 'index.html';
    137
    138 // join / normalize from optional root dir
    13935 path = normalize(join(root, path));
    140
    141 // malicious path
    14237 if (root && 0 != path.indexOf(root)) return next(utils.error(403));
    143
    144 // "hidden" file
    14534 if (!hidden && '.' == basename(path)[0]) return next();
    146
    14732 fs.stat(path, function(err, stat){
    148 // mime type
    14932 type = mime.lookup(path);
    150
    151 // ignore ENOENT
    15232 if (err) {
    1531 if (fn) return fn(err);
    1541 return ('ENOENT' == err.code || 'ENAMETOOLONG' == err.code)
    155 ? next()
    156 : next(err);
    157 // redirect directory in case index.html is present
    15831 } else if (stat.isDirectory()) {
    1591 if (!redirect) return next();
    1601 res.statusCode = 301;
    1611 res.setHeader('Location', url.pathname + '/');
    1621 res.end('Redirecting to ' + url.pathname + '/');
    1631 return;
    164 }
    165
    166 // header fields
    16760 if (!res.getHeader('Date')) res.setHeader('Date', new Date().toUTCString());
    16858 if (!res.getHeader('Cache-Control')) res.setHeader('Cache-Control', 'public, max-age=' + (maxAge / 1000));
    16960 if (!res.getHeader('Last-Modified')) res.setHeader('Last-Modified', stat.mtime.toUTCString());
    17030 if (!res.getHeader('Content-Type')) {
    17130 var charset = mime.charsets.lookup(type);
    17230 res.setHeader('Content-Type', type + (charset ? '; charset=' + charset : ''));
    173 }
    17430 res.setHeader('Accept-Ranges', 'bytes');
    175
    176 // conditional GET support
    17730 if (utils.conditionalGET(req)) {
    1781 if (!utils.modified(req, res)) {
    1791 req.emit('static');
    1801 return utils.notModified(res);
    181 }
    182 }
    183
    18429 var opts = {}
    185 , len = stat.size;
    186
    187 // we have a Range request
    18829 if (ranges) {
    1897 ranges = utils.parseRange(stat.size, ranges);
    190 // valid
    1917 if (ranges) {
    192 // TODO: stream options
    193 // TODO: multiple support
    1946 opts.start = ranges[0].start;
    1956 opts.end = ranges[0].end;
    1966 len = Math.min(len, opts.end - opts.start + 1);
    1976 res.statusCode = 206;
    1986 res.setHeader('Content-Range', 'bytes '
    199 + opts.start
    200 + '-'
    201 + opts.end
    202 + '/'
    203 + stat.size);
    204 // invalid range
    205 } else {
    2061 return next(utils.error(416));
    207 }
    208 }
    209
    21028 res.setHeader('Content-Length', len);
    211
    212 // transfer
    21332 if (head) return res.end();
    214
    215 // stream
    21624 var stream = fs.createReadStream(path, opts);
    21724 req.emit('static', stream);
    21824 req.on('close', stream.destroy.bind(stream));
    21924 stream.pipe(res);
    220
    221 // callback
    22224 if (fn) {
    2230 function callback(err) { done || fn(err); done = true }
    2240 req.on('close', callback);
    2250 req.socket.on('error', callback);
    2260 stream.on('error', callback);
    2270 stream.on('end', callback);
    228 } else {
    22924 stream.on('error', function(err){
    2301 if (res.headerSent) {
    2310 console.error(err.stack);
    2320 req.destroy();
    233 } else {
    2341 next(err);
    235 }
    236 });
    237 }
    238 });
    239};

    middleware/limit.js

    88%
    17
    15
    2
    LineHitsSource
    1
    2/*!
    3 * Connect - limit
    4 * Copyright(c) 2011 TJ Holowaychuk
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Module dependencies.
    10 */
    11
    121var utils = require('../utils');
    13
    14/**
    15 * Limit:
    16 *
    17 * Limit request bodies to the given size in `bytes`.
    18 *
    19 * A string representation of the bytesize may also be passed,
    20 * for example "5mb", "200kb", "1gb", etc.
    21 *
    22 * connect()
    23 * .use(connect.limit('5.5mb'))
    24 * .use(handleImageUpload)
    25 *
    26 * @param {Number|String} bytes
    27 * @return {Function}
    28 * @api public
    29 */
    30
    311module.exports = function limit(bytes){
    322 if ('string' == typeof bytes) bytes = parse(bytes);
    331 if ('number' != typeof bytes) throw new Error('limit() bytes required');
    341 return function limit(req, res, next){
    352 var received = 0
    36 , len = req.headers['content-length']
    37 ? parseInt(req.headers['content-length'], 10)
    38 : null;
    39
    40 // self-awareness
    412 if (req._limit) return next();
    422 req._limit = true;
    43
    44 // limit by content-length
    453 if (len && len > bytes) return next(utils.error(413));
    46
    47 // limit
    481 req.on('data', function(chunk){
    490 received += chunk.length;
    500 if (received > bytes) req.destroy();
    51 });
    52
    531 next();
    54 };
    55};
    56
    57/**
    58 * Parse byte `size` string.
    59 *
    60 * @param {String} size
    61 * @return {Number}
    62 * @api private
    63 */
    64
    651function parse(size) {
    661 var parts = size.match(/^(\d+(?:\.\d+)?) *(kb|mb|gb)$/)
    67 , n = parseFloat(parts[1])
    68 , type = parts[2];
    69
    701 var map = {
    71 kb: 1024
    72 , mb: 1024 * 1024
    73 , gb: 1024 * 1024 * 1024
    74 };
    75
    761 return map[type] * n;
    77}

    middleware/query.js

    100%
    5
    5
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - query
    4 * Copyright(c) 2011 TJ Holowaychuk
    5 * Copyright(c) 2011 Sencha Inc.
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var qs = require('qs')
    14 , parse = require('url').parse;
    15
    16/**
    17 * Query:
    18 *
    19 * Automatically parse the query-string when available,
    20 * populating the `req.query` object.
    21 *
    22 * Examples:
    23 *
    24 * connect()
    25 * .use(connect.query())
    26 * .use(function(req, res){
    27 * res.end(JSON.stringify(req.query));
    28 * });
    29 *
    30 * @return {Function}
    31 * @api public
    32 */
    33
    341module.exports = function query(){
    351 return function query(req, res, next){
    362 req.query = ~req.url.indexOf('?')
    37 ? qs.parse(parse(req.url).query)
    38 : {};
    392 next();
    40 };
    41};

    middleware/responseTime.js

    100%
    9
    9
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - responseTime
    4 * Copyright(c) 2011 TJ Holowaychuk
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Reponse time:
    10 *
    11 * Adds the `X-Response-Time` header displaying the response
    12 * duration in milliseconds.
    13 *
    14 * @return {Function}
    15 * @api public
    16 */
    17
    181module.exports = function responseTime(){
    191 return function(req, res, next){
    201 var start = new Date;
    21
    221 if (res._responseTime) return next();
    231 res._responseTime = true;
    24
    251 res.on('header', function(header){
    261 var duration = new Date - start;
    271 res.setHeader('X-Response-time', duration + 'ms');
    28 });
    29
    301 next();
    31 };
    32};

    middleware/cookieParser.js

    94%
    17
    16
    1
    LineHitsSource
    1
    2/*!
    3 * Connect - cookieParser
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var utils = require('./../utils');
    14
    15/**
    16 * Cookie parser:
    17 *
    18 * Parse _Cookie_ header and populate `req.cookies`
    19 * with an object keyed by the cookie names. Optionally
    20 * you may enabled signed cookie support by passing
    21 * a `secret` string, which assigns `req.secret` so
    22 * it may be used by other middleware such as `session()`.
    23 *
    24 * Examples:
    25 *
    26 * connect()
    27 * .use(connect.cookieParser('keyboard cat'))
    28 * .use(function(req, res, next){
    29 * res.end(JSON.stringify(req.cookies));
    30 * })
    31 *
    32 * @param {String} secret
    33 * @return {Function}
    34 * @api public
    35 */
    36
    371module.exports = function cookieParser(secret){
    3829 return function cookieParser(req, res, next) {
    3935 var cookie = req.headers.cookie;
    4035 if (req.cookies) return next();
    41
    4235 req.secret = secret;
    4335 req.cookies = {};
    4435 req.signedCookies = {};
    45
    4635 if (cookie) {
    478 try {
    488 req.cookies = utils.parseCookie(cookie);
    498 if (secret) {
    508 req.signedCookies = utils.parseSignedCookies(req.cookies, secret);
    518 req.signedCookies = utils.parseJSONCookies(req.signedCookies);
    52 }
    538 req.cookies = utils.parseJSONCookies(req.cookies);
    54 } catch (err) {
    550 return next(err);
    56 }
    57 }
    5835 next();
    59 };
    60};

    middleware/session.js

    86%
    67
    58
    9
    LineHitsSource
    1
    2/*!
    3 * Connect - session
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var Session = require('./session/session')
    14 , debug = require('debug')('connect:session')
    15 , MemoryStore = require('./session/memory')
    16 , Cookie = require('./session/cookie')
    17 , Store = require('./session/store')
    18 , utils = require('./../utils')
    19 , parse = require('url').parse
    20 , crypto = require('crypto');
    21
    22// environment
    23
    241var env = process.env.NODE_ENV;
    25
    26/**
    27 * Expose the middleware.
    28 */
    29
    301exports = module.exports = session;
    31
    32/**
    33 * Expose constructors.
    34 */
    35
    361exports.Store = Store;
    371exports.Cookie = Cookie;
    381exports.Session = Session;
    391exports.MemoryStore = MemoryStore;
    40
    41/**
    42 * Warning message for `MemoryStore` usage in production.
    43 */
    44
    451var warning = 'Warning: connection.session() MemoryStore is not\n'
    46 + 'designed for a production environment, as it will leak\n'
    47 + 'memory, and obviously only work within a single process.';
    48
    49/**
    50 * Session:
    51 *
    52 * Setup session store with the given `options`.
    53 *
    54 * Session data is _not_ saved in the cookie itself, however
    55 * cookies are used, so we must use the [cookieParser()](cookieParser.html)
    56 * middleware _before_ `session()`.
    57 *
    58 * Examples:
    59 *
    60 * connect()
    61 * .use(connect.cookieParser('keyboard cat'))
    62 * .use(connect.session({ key: 'sid', cookie: { secure: true }}))
    63 *
    64 * Options:
    65 *
    66 * - `key` cookie name defaulting to `connect.sid`
    67 * - `store` session store instance
    68 * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
    69 * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
    70 *
    71 * Cookie option:
    72 *
    73 * By default `cookie.maxAge` is `null`, meaning no "expires" parameter is set
    74 * so the cookie becomes a browser-session cookie. When the user closes the
    75 * browser the cookie (and session) will be removed.
    76 *
    77 * ## req.session
    78 *
    79 * To store or access session data, simply use the request property `req.session`,
    80 * which is (generally) serialized as JSON by the store, so nested objects
    81 * are typically fine. For example below is a user-specific view counter:
    82 *
    83 * connect()
    84 * .use(connect.favicon())
    85 * .use(connect.cookieParser('keyboard cat'))
    86 * .use(connect.session({ cookie: { maxAge: 60000 }}))
    87 * .use(function(req, res, next){
    88 * var sess = req.session;
    89 * if (sess.views) {
    90 * res.setHeader('Content-Type', 'text/html');
    91 * res.write('<p>views: ' + sess.views + '</p>');
    92 * res.write('<p>expires in: ' + (sess.cookie.maxAge / 1000) + 's</p>');
    93 * res.end();
    94 * sess.views++;
    95 * } else {
    96 * sess.views = 1;
    97 * res.end('welcome to the session demo. refresh!');
    98 * }
    99 * }
    100 * )).listen(3000);
    101 *
    102 * ## Session#regenerate()
    103 *
    104 * To regenerate the session simply invoke the method, once complete
    105 * a new SID and `Session` instance will be initialized at `req.session`.
    106 *
    107 * req.session.regenerate(function(err){
    108 * // will have a new session here
    109 * });
    110 *
    111 * ## Session#destroy()
    112 *
    113 * Destroys the session, removing `req.session`, will be re-generated next request.
    114 *
    115 * req.session.destroy(function(err){
    116 * // cannot access session here
    117 * });
    118 *
    119 * ## Session#reload()
    120 *
    121 * Reloads the session data.
    122 *
    123 * req.session.reload(function(err){
    124 * // session updated
    125 * });
    126 *
    127 * ## Session#save()
    128 *
    129 * Save the session.
    130 *
    131 * req.session.save(function(err){
    132 * // session saved
    133 * });
    134 *
    135 * ## Session#touch()
    136 *
    137 * Updates the `.maxAge`, and `.lastAccess` properties. Typically this is
    138 * not necessary to call, as the session middleware does this for you.
    139 *
    140 * ## Session#cookie
    141 *
    142 * Each session has a unique cookie object accompany it. This allows
    143 * you to alter the session cookie per visitor. For example we can
    144 * set `req.session.cookie.expires` to `false` to enable the cookie
    145 * to remain for only the duration of the user-agent.
    146 *
    147 * ## Session#maxAge
    148 *
    149 * Alternatively `req.session.cookie.maxAge` will return the time
    150 * remaining in milliseconds, which we may also re-assign a new value
    151 * to adjust the `.expires` property appropriately. The following
    152 * are essentially equivalent
    153 *
    154 * var hour = 3600000;
    155 * req.session.cookie.expires = new Date(Date.now() + hour);
    156 * req.session.cookie.maxAge = hour;
    157 *
    158 * For example when `maxAge` is set to `60000` (one minute), and 30 seconds
    159 * has elapsed it will return `30000` until the current request has completed,
    160 * at which time `req.session.touch()` is called to update `req.session.lastAccess`,
    161 * and reset `req.session.maxAge` to its original value.
    162 *
    163 * req.session.cookie.maxAge;
    164 * // => 30000
    165 *
    166 * Session Store Implementation:
    167 *
    168 * Every session store _must_ implement the following methods
    169 *
    170 * - `.get(sid, callback)`
    171 * - `.set(sid, session, callback)`
    172 * - `.destroy(sid, callback)`
    173 *
    174 * Recommended methods include, but are not limited to:
    175 *
    176 * - `.length(callback)`
    177 * - `.clear(callback)`
    178 *
    179 * For an example implementation view the [connect-redis](http://github.com/visionmedia/connect-redis) repo.
    180 *
    181 * @param {Object} options
    182 * @return {Function}
    183 * @api public
    184 */
    185
    1861function session(options){
    18715 var options = options || {}
    188 , key = options.key || 'connect.sid'
    189 , store = options.store || new MemoryStore
    190 , cookie = options.cookie
    191 , trustProxy = options.proxy;
    192
    193 // notify user that this store is not
    194 // meant for a production environment
    19515 if ('production' == env && store instanceof MemoryStore) {
    1960 console.warn(warning);
    197 }
    198
    199 // generates the new session
    20015 store.generate = function(req){
    20121 req.sessionID = utils.uid(24);
    20221 req.session = new Session(req);
    20321 req.session.cookie = new Cookie(req, cookie);
    204 };
    205
    20615 return function session(req, res, next) {
    207 // self-awareness
    20824 if (req.session) return next();
    209
    210 // ensure secret is available or bail
    21124 if (!req.secret) throw new Error('connect.cookieParser("secret") required for security when using sessions');
    212
    213 // parse url
    21424 var url = parse(req.url)
    215 , path = url.pathname
    216 , sessionIsNew;
    217
    218 // expose store
    21924 req.sessionStore = store;
    220
    221 // set-cookie
    22224 res.on('header', function(){
    22325 if (!req.session) return;
    22423 var cookie = req.session.cookie
    225 , proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
    226 , tls = req.connection.encrypted || (trustProxy && 'https' == proto)
    227 , secured = cookie.secure && tls;
    228
    229 // browser-session cookies only set-cookie once
    23024 if (null == cookie.expires && !sessionIsNew) return;
    231
    232 // only send secure cookies via https
    23324 if (cookie.secure && !secured) return debug('not secured');
    234
    23520 debug('set %s to %s', key, req.sessionID);
    23620 res.setHeader('Set-Cookie', cookie.serialize(key, req.sessionID));
    237 });
    238
    239 // proxy end() to commit the session
    24024 var end = res.end;
    24124 res.end = function(data, encoding){
    24224 res.end = end;
    24325 if (!req.session) return res.end(data, encoding);
    24423 debug('saving');
    24523 req.session.resetMaxAge();
    24623 req.session.save(function(){
    24723 debug('saved');
    24823 res.end(data, encoding);
    249 });
    250 };
    251
    252 // generate the session
    25324 function generate() {
    25419 sessionIsNew = true;
    25519 store.generate(req);
    256 }
    257
    258 // get the sessionID from the cookie
    25924 req.sessionID = req.signedCookies[key];
    260
    261 // generate a session if the browser doesn't send a sessionID
    26224 if (!req.sessionID) {
    26319 debug('no SID sent, generating session');
    26419 generate();
    26519 next();
    26619 return;
    267 }
    268
    269 // generate the session object
    2705 var pause = utils.pause(req);
    2715 debug('fetching %s', req.sessionID);
    2725 store.get(req.sessionID, function(err, sess){
    273 // proxy to resume() events
    2745 var _next = next;
    2755 next = function(err){
    2765 _next(err);
    2775 pause.resume();
    278 }
    279
    280 // error handling
    2815 if (err) {
    2820 debug('error');
    2830 if ('ENOENT' == err.code) {
    2840 generate();
    2850 next();
    286 } else {
    2870 next(err);
    288 }
    289 // no session
    2905 } else if (!sess) {
    2910 debug('no session found');
    2920 generate();
    2930 next();
    294 // populate req.session
    295 } else {
    2965 debug('session found');
    2975 store.createSession(req, sess);
    2985 next();
    299 }
    300 });
    301 };
    3021};

    middleware/session/session.js

    75%
    33
    25
    8
    LineHitsSource
    1
    2/*!
    3 * Connect - session - Session
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var utils = require('../../utils')
    14 , Cookie = require('./cookie');
    15
    16/**
    17 * Create a new `Session` with the given request and `data`.
    18 *
    19 * @param {IncomingRequest} req
    20 * @param {Object} data
    21 * @api private
    22 */
    23
    241var Session = module.exports = function Session(req, data) {
    2526 Object.defineProperty(this, 'req', { value: req });
    2626 Object.defineProperty(this, 'id', { value: req.sessionID });
    2726 if ('object' == typeof data) {
    285 utils.merge(this, data);
    29 } else {
    3021 this.lastAccess = Date.now();
    31 }
    32};
    33
    34/**
    35 * Update `.lastAccess` timestamp,
    36 * and reset `.cookie.maxAge` to prevent
    37 * the cookie from expiring when the
    38 * session is still active.
    39 *
    40 * @return {Session} for chaining
    41 * @api public
    42 */
    43
    441Session.prototype.touch = function(){
    450 return this
    46 .resetLastAccess()
    47 .resetMaxAge();
    48};
    49
    50/**
    51 * Update `.lastAccess` timestamp.
    52 *
    53 * @return {Session} for chaining
    54 * @api public
    55 */
    56
    571Session.prototype.resetLastAccess = function(){
    585 this.lastAccess = Date.now();
    595 return this;
    60};
    61
    62/**
    63 * Reset `.maxAge` to `.originalMaxAge`.
    64 *
    65 * @return {Session} for chaining
    66 * @api public
    67 */
    68
    691Session.prototype.resetMaxAge = function(){
    7023 this.cookie.maxAge = this.cookie.originalMaxAge;
    7123 return this;
    72};
    73
    74/**
    75 * Save the session data with optional callback `fn(err)`.
    76 *
    77 * @param {Function} fn
    78 * @return {Session} for chaining
    79 * @api public
    80 */
    81
    821Session.prototype.save = function(fn){
    8323 this.req.sessionStore.set(this.id, this, fn || function(){});
    8423 return this;
    85};
    86
    87/**
    88 * Re-loads the session data _without_ altering
    89 * the maxAge or lastAccess properties. Invokes the
    90 * callback `fn(err)`, after which time if no exception
    91 * has occurred the `req.session` property will be
    92 * a new `Session` object, although representing the
    93 * same session.
    94 *
    95 * @param {Function} fn
    96 * @return {Session} for chaining
    97 * @api public
    98 */
    99
    1001Session.prototype.reload = function(fn){
    1010 var req = this.req
    102 , store = this.req.sessionStore;
    1030 store.get(this.id, function(err, sess){
    1040 if (err) return fn(err);
    1050 if (!sess) return fn(new Error('failed to load session'));
    1060 store.createSession(req, sess);
    1070 fn();
    108 });
    1090 return this;
    110};
    111
    112/**
    113 * Destroy `this` session.
    114 *
    115 * @param {Function} fn
    116 * @return {Session} for chaining
    117 * @api public
    118 */
    119
    1201Session.prototype.destroy = function(fn){
    1211 delete this.req.session;
    1221 this.req.sessionStore.destroy(this.id, fn);
    1231 return this;
    124};
    125
    126/**
    127 * Regenerate this request's session.
    128 *
    129 * @param {Function} fn
    130 * @return {Session} for chaining
    131 * @api public
    132 */
    133
    1341Session.prototype.regenerate = function(fn){
    1352 this.req.sessionStore.regenerate(this.req, fn);
    1362 return this;
    137};

    middleware/session/cookie.js

    100%
    18
    18
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - session - Cookie
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var utils = require('../../utils');
    14
    15/**
    16 * Initialize a new `Cookie` with the given `options`.
    17 *
    18 * @param {IncomingMessage} req
    19 * @param {Object} options
    20 * @api private
    21 */
    22
    231var Cookie = module.exports = function Cookie(req, options) {
    2437 this.path = '/';
    2537 this.maxAge = null;
    2637 this.httpOnly = true;
    2761 if (options) utils.merge(this, options);
    2837 Object.defineProperty(this, 'req', { value: req });
    2937 this.originalMaxAge = undefined == this.originalMaxAge
    30 ? this.maxAge
    31 : this.originalMaxAge;
    32};
    33
    34/*!
    35 * Prototype.
    36 */
    37
    381Cookie.prototype = {
    39
    40 /**
    41 * Set expires `date`.
    42 *
    43 * @param {Date} date
    44 * @api public
    45 */
    46
    47 set expires(date) {
    4886 this._expires = date;
    4986 this.originalMaxAge = this.maxAge;
    50 },
    51
    52 /**
    53 * Get expires `date`.
    54 *
    55 * @return {Date}
    56 * @api public
    57 */
    58
    59 get expires() {
    60241 return this._expires;
    61 },
    62
    63 /**
    64 * Set expires via max-age in `ms`.
    65 *
    66 * @param {Number} ms
    67 * @api public
    68 */
    69
    70 set maxAge(ms) {
    7175 this.expires = 'number' == typeof ms
    72 ? new Date(Date.now() + ms)
    73 : ms;
    74 },
    75
    76 /**
    77 * Get expires max-age in `ms`.
    78 *
    79 * @return {Number}
    80 * @api public
    81 */
    82
    83 get maxAge() {
    84105 return this.expires instanceof Date
    85 ? this.expires.valueOf() - Date.now()
    86 : this.expires;
    87 },
    88
    89 /**
    90 * Return cookie data object.
    91 *
    92 * @return {Object}
    93 * @api private
    94 */
    95
    96 get data() {
    9743 return {
    98 originalMaxAge: this.originalMaxAge
    99 , expires: this._expires
    100 , secure: this.secure
    101 , httpOnly: this.httpOnly
    102 , domain: this.domain
    103 , path: this.path
    104 }
    105 },
    106
    107 /**
    108 * Return a serialized cookie string.
    109 *
    110 * @return {String}
    111 * @api public
    112 */
    113
    114 serialize: function(name, val){
    11520 val = utils.sign(val, this.req.secret);
    11620 return utils.serializeCookie(name, val, this.data);
    117 },
    118
    119 /**
    120 * Return JSON representation of this cookie.
    121 *
    122 * @return {Object}
    123 * @api private
    124 */
    125
    126 toJSON: function(){
    12723 return this.data;
    128 }
    129};

    middleware/session/memory.js

    74%
    35
    26
    9
    LineHitsSource
    1
    2/*!
    3 * Connect - session - MemoryStore
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var Store = require('./store')
    14 , utils = require('../../utils')
    15 , Session = require('./session');
    16
    17/**
    18 * Initialize a new `MemoryStore`.
    19 *
    20 * @api public
    21 */
    22
    231var MemoryStore = module.exports = function MemoryStore() {
    2415 this.sessions = {};
    25};
    26
    27/**
    28 * Inherit from `Store.prototype`.
    29 */
    30
    311MemoryStore.prototype.__proto__ = Store.prototype;
    32
    33/**
    34 * Attempt to fetch session by the given `sid`.
    35 *
    36 * @param {String} sid
    37 * @param {Function} fn
    38 * @api public
    39 */
    40
    411MemoryStore.prototype.get = function(sid, fn){
    425 var self = this;
    435 process.nextTick(function(){
    445 var expires
    45 , sess = self.sessions[sid];
    465 if (sess) {
    475 sess = JSON.parse(sess);
    485 expires = 'string' == typeof sess.cookie.expires
    49 ? new Date(sess.cookie.expires)
    50 : sess.cookie.expires;
    515 if (!expires || new Date < expires) {
    525 fn(null, sess);
    53 } else {
    540 self.destroy(sid, fn);
    55 }
    56 } else {
    570 fn();
    58 }
    59 });
    60};
    61
    62/**
    63 * Commit the given `sess` object associated with the given `sid`.
    64 *
    65 * @param {String} sid
    66 * @param {Session} sess
    67 * @param {Function} fn
    68 * @api public
    69 */
    70
    711MemoryStore.prototype.set = function(sid, sess, fn){
    7223 var self = this;
    7323 process.nextTick(function(){
    7423 self.sessions[sid] = JSON.stringify(sess);
    7523 fn && fn();
    76 });
    77};
    78
    79/**
    80 * Destroy the session associated with the given `sid`.
    81 *
    82 * @param {String} sid
    83 * @api public
    84 */
    85
    861MemoryStore.prototype.destroy = function(sid, fn){
    873 var self = this;
    883 process.nextTick(function(){
    893 delete self.sessions[sid];
    903 fn && fn();
    91 });
    92};
    93
    94/**
    95 * Invoke the given callback `fn` with all active sessions.
    96 *
    97 * @param {Function} fn
    98 * @api public
    99 */
    100
    1011MemoryStore.prototype.all = function(fn){
    1020 var arr = []
    103 , keys = Object.keys(this.sessions);
    1040 for (var i = 0, len = keys.length; i < len; ++i) {
    1050 arr.push(this.sessions[keys[i]]);
    106 }
    1070 fn(null, arr);
    108};
    109
    110/**
    111 * Clear all sessions.
    112 *
    113 * @param {Function} fn
    114 * @api public
    115 */
    116
    1171MemoryStore.prototype.clear = function(fn){
    1180 this.sessions = {};
    1190 fn && fn();
    120};
    121
    122/**
    123 * Fetch number of sessions.
    124 *
    125 * @param {Function} fn
    126 * @api public
    127 */
    128
    1291MemoryStore.prototype.length = function(fn){
    1300 fn(null, Object.keys(this.sessions).length);
    131};

    middleware/session/store.js

    70%
    24
    17
    7
    LineHitsSource
    1
    2/*!
    3 * Connect - session - Store
    4 * Copyright(c) 2010 Sencha Inc.
    5 * Copyright(c) 2011 TJ Holowaychuk
    6 * MIT Licensed
    7 */
    8
    9/**
    10 * Module dependencies.
    11 */
    12
    131var EventEmitter = require('events').EventEmitter
    14 , Session = require('./session')
    15 , Cookie = require('./cookie')
    16 , utils = require('../../utils');
    17
    18/**
    19 * Initialize abstract `Store`.
    20 *
    21 * @api private
    22 */
    23
    241var Store = module.exports = function Store(options){};
    25
    26/**
    27 * Inherit from `EventEmitter.prototype`.
    28 */
    29
    301Store.prototype.__proto__ = EventEmitter.prototype;
    31
    32/**
    33 * Re-generate the given requests's session.
    34 *
    35 * @param {IncomingRequest} req
    36 * @return {Function} fn
    37 * @api public
    38 */
    39
    401Store.prototype.regenerate = function(req, fn){
    412 var self = this;
    422 this.destroy(req.sessionID, function(err){
    432 self.generate(req);
    442 fn(err);
    45 });
    46};
    47
    48/**
    49 * Load a `Session` instance via the given `sid`
    50 * and invoke the callback `fn(err, sess)`.
    51 *
    52 * @param {String} sid
    53 * @param {Function} fn
    54 * @api public
    55 */
    56
    571Store.prototype.load = function(sid, fn){
    580 var self = this;
    590 this.get(sid, function(err, sess){
    600 if (err) return fn(err);
    610 if (!sess) return fn();
    620 var req = { sessionID: sid, sessionStore: self };
    630 sess = self.createSession(req, sess, false);
    640 fn(null, sess);
    65 });
    66};
    67
    68/**
    69 * Create session from JSON `sess` data.
    70 *
    71 * @param {IncomingRequest} req
    72 * @param {Object} sess
    73 * @return {Session}
    74 * @api private
    75 */
    76
    771Store.prototype.createSession = function(req, sess, update){
    785 var expires = sess.cookie.expires
    79 , orig = sess.cookie.originalMaxAge
    80 , update = null == update ? true : false;
    815 sess.cookie = new Cookie(req, sess.cookie);
    829 if ('string' == typeof expires) sess.cookie.expires = new Date(expires);
    835 sess.cookie.originalMaxAge = orig;
    845 req.session = new Session(req, sess);
    8510 if (update) req.session.resetLastAccess();
    865 return req.session;
    87};

    middleware/staticCache.js

    85%
    54
    46
    8
    LineHitsSource
    1
    2/*!
    3 * Connect - staticCache
    4 * Copyright(c) 2011 Sencha Inc.
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Module dependencies.
    10 */
    11
    121var http = require('http')
    13 , utils = require('../utils')
    14 , Cache = require('../cache')
    15 , url = require('url')
    16 , fs = require('fs');
    17
    18/**
    19 * Static cache:
    20 *
    21 * Enables a memory cache layer on top of
    22 * the `static()` middleware, serving popular
    23 * static files.
    24 *
    25 * By default a maximum of 128 objects are
    26 * held in cache, with a max of 256k each,
    27 * totalling ~32mb.
    28 *
    29 * A Least-Recently-Used (LRU) cache algo
    30 * is implemented through the `Cache` object,
    31 * simply rotating cache objects as they are
    32 * hit. This means that increasingly popular
    33 * objects maintain their positions while
    34 * others get shoved out of the stack and
    35 * garbage collected.
    36 *
    37 * Benchmarks:
    38 *
    39 * static(): 2700 rps
    40 * node-static: 5300 rps
    41 * static() + staticCache(): 7500 rps
    42 *
    43 * Options:
    44 *
    45 * - `maxObjects` max cache objects [128]
    46 * - `maxLength` max cache object length 256kb
    47 *
    48 * @param {Type} name
    49 * @return {Type}
    50 * @api public
    51 */
    52
    531module.exports = function staticCache(options){
    543 var options = options || {}
    55 , cache = new Cache(options.maxObjects || 128)
    56 , maxlen = options.maxLength || 1024 * 256;
    57
    583 return function staticCache(req, res, next){
    5910 var path = url.parse(req.url).pathname
    60 , ranges = req.headers.range
    61 , hit = cache.get(path)
    62 , hitCC
    63 , uaCC
    64 , header
    65 , age;
    66
    6710 function miss() {
    684 res.setHeader('X-Cache', 'MISS');
    694 next();
    70 }
    71
    72 // cache static
    73 // TODO: change from staticCache() -> static()
    74 // and make this work for any request
    7510 req.on('static', function(stream){
    762 var headers = res._headers
    77 , cc = utils.parseCacheControl(headers['cache-control'] || '')
    78 , contentLength = headers['content-length']
    79 , hit;
    80
    81 // ignore larger files
    822 if (!contentLength || contentLength > maxlen) return;
    83
    84 // dont cache items we shouldn't be
    85 // TODO: real support for must-revalidate / no-cache
    862 if ( cc['no-cache']
    87 || cc['no-store']
    88 || cc['private']
    890 || cc['must-revalidate']) return;
    90
    91 // if already in cache then validate
    922 if (hit = cache.get(path)){
    931 if (headers.etag == hit[0].etag) {
    941 hit[0].date = new Date;
    951 return;
    96 } else {
    970 cache.remove(path);
    98 }
    99 }
    100
    101 // validation notifiactions don't contain a steam
    1021 if (null == stream) return;
    103
    104 // add the cache object
    1051 var arr = cache.add(path);
    1061 arr.push(headers);
    107
    108 // store the chunks
    1091 stream.on('data', function(chunk){
    1101 arr.push(chunk);
    111 });
    112
    113 // flag it as complete
    1141 stream.on('end', function(){
    1151 arr.complete = true;
    116 });
    117 });
    118
    119 // cache hit, doesnt support range requests
    12010 if (hit && hit.complete && !ranges) {
    1217 header = utils.merge({}, hit[0]);
    1227 header.Age = age = (new Date - new Date(header.date)) / 1000 | 0;
    1237 header.date = new Date().toUTCString();
    124
    125 // parse cache-controls
    1267 hitCC = utils.parseCacheControl(header['cache-control'] || '');
    1277 uaCC = utils.parseCacheControl(req.headers['cache-control'] || '');
    128
    129 // check if we must revalidate(bypass)
    1308 if (hitCC['no-cache'] || uaCC['no-cache']) return miss();
    131
    132 // check freshness of entity
    1336 if (isStale(hitCC, age) || isStale(uaCC, age)) return miss();
    134
    135 // conditional GET support
    1366 if (utils.conditionalGET(req)) {
    1370 if (!utils.modified(req, res, header)) {
    1380 header['content-length'] = 0;
    1390 res.writeHead(304, header);
    1400 return res.end();
    141 }
    142 }
    143
    144 // HEAD support
    1456 if ('HEAD' == req.method) {
    1462 res.writeHead(200, header);
    1472 return res.end();
    148 }
    149
    150 // respond with cache
    1514 header['x-cache'] = 'HIT';
    1524 res.writeHead(200, header);
    153
    154 // backpressure
    1554 function write(i) {
    1568 var buf = hit[i];
    15712 if (!buf) return res.end();
    1584 if (false === res.write(buf)) {
    1590 res.once('drain', function(){
    1600 write(++i);
    161 });
    162 } else {
    1634 write(++i);
    164 }
    165 }
    166
    1674 return write(1);
    168 }
    169
    1703 miss();
    171 }
    172};
    173
    174/**
    175 * Check if cache item is stale
    176 *
    177 * @param {Object} cc
    178 * @param {Number} age
    179 * @return {Boolean}
    180 * @api private
    181 */
    182
    1831function isStale(cc, age) {
    18412 return cc['max-age'] && cc['max-age'] <= age;
    185}

    cache.js

    83%
    18
    15
    3
    LineHitsSource
    1
    2/*!
    3 * Connect - Cache
    4 * Copyright(c) 2011 Sencha Inc.
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Expose `Cache`.
    10 */
    11
    121module.exports = Cache;
    13
    14/**
    15 * LRU cache store.
    16 *
    17 * @param {Number} limit
    18 * @api private
    19 */
    20
    211function Cache(limit) {
    223 this.store = {};
    233 this.keys = [];
    243 this.limit = limit;
    25}
    26
    27/**
    28 * Touch `key`, promoting the object.
    29 *
    30 * @param {String} key
    31 * @param {Number} i
    32 * @api private
    33 */
    34
    351Cache.prototype.touch = function(key, i){
    360 this.keys.splice(i,1);
    370 this.keys.push(key);
    38};
    39
    40/**
    41 * Remove `key`.
    42 *
    43 * @param {String} key
    44 * @api private
    45 */
    46
    471Cache.prototype.remove = function(key){
    480 delete this.store[key];
    49};
    50
    51/**
    52 * Get the object stored for `key`.
    53 *
    54 * @param {String} key
    55 * @return {Array}
    56 * @api private
    57 */
    58
    591Cache.prototype.get = function(key){
    6012 return this.store[key];
    61};
    62
    63/**
    64 * Add a cache `key`.
    65 *
    66 * @param {String} key
    67 * @return {Array}
    68 * @api private
    69 */
    70
    711Cache.prototype.add = function(key){
    72 // initialize store
    731 var len = this.keys.push(key);
    74
    75 // limit reached, invalidate LRU
    761 if (len > this.limit) this.remove(this.keys.shift());
    77
    781 var arr = this.store[key] = [];
    791 arr.createdAt = new Date;
    801 return arr;
    81};

    middleware/cookieSession.js

    100%
    23
    23
    0
    LineHitsSource
    1
    2/*!
    3 * Connect - cookieSession
    4 * Copyright(c) 2011 Sencha Inc.
    5 * MIT Licensed
    6 */
    7
    8/**
    9 * Module dependencies.
    10 */
    11
    121var utils = require('./../utils')
    13 , Cookie = require('./session/cookie')
    14 , debug = require('debug')('connect:cookieSession');
    15
    16// environment
    17
    181var env = process.env.NODE_ENV;
    19
    20/**
    21 * Cookie Session:
    22 *
    23 * Cookie session middleware.
    24 *
    25 * var app = connect();
    26 * app.use(connect.cookieParser('tobo!'));
    27 * app.use(connect.cookieSession({ cookie: { maxAge: 60 * 60 * 1000 }}));
    28 *
    29 * Options:
    30 *
    31 * - `key` cookie name defaulting to `connect.sess`
    32 * - `cookie` session cookie settings, defaulting to `{ path: '/', httpOnly: true, maxAge: null }`
    33 * - `proxy` trust the reverse proxy when setting secure cookies (via "x-forwarded-proto")
    34 *
    35 * @param {Object} options
    36 * @return {Function}
    37 * @api public
    38 */
    39
    401module.exports = function cookieSession(options){
    41 // TODO: utilize Session/Cookie to unify API
    42 // TODO: only set-cookie on changes to the session data
    43
    4414 var options = options || {}
    45 , key = options.key || 'connect.sess'
    46 , cookie = options.cookie
    47 , trustProxy = options.proxy;
    48
    4914 return function cookieSession(req, res, next) {
    5011 req.session = req.signedCookies[key] || {};
    5111 req.session.cookie = new Cookie(req, cookie);
    52
    5311 res.on('header', function(){
    54 // removed
    5511 if (!req.session) {
    561 debug('clear session');
    571 res.setHeader('Set-Cookie', key + '=; expires=' + new Date(0).toUTCString());
    581 return;
    59 }
    60
    6110 var cookie = req.session.cookie;
    6210 delete req.session.cookie;
    63
    64 // check security
    6510 var proto = (req.headers['x-forwarded-proto'] || '').toLowerCase()
    66 , tls = req.connection.encrypted || (trustProxy && 'https' == proto)
    67 , secured = cookie.secure && tls;
    68
    69 // only send secure cookies via https
    7012 if (cookie.secure && !secured) return debug('not secured');
    71
    72 // set cookie
    738 debug('serializing %j', req.session);
    748 var val = 'j:' + JSON.stringify(req.session);
    758 val = utils.sign(val, req.secret);
    768 val = utils.serializeCookie(key, val, cookie);
    778 debug('cookie %j', cookie);
    788 res.setHeader('Set-Cookie', val);
    79 });
    80
    8111 next();
    82 };
    83};
    \ No newline at end of file diff --git a/normalize.min.css b/css/normalize.min.css similarity index 100% rename from normalize.min.css rename to css/normalize.min.css diff --git a/css/pygments.css b/css/pygments.css new file mode 100644 index 0000000000..851ba3c1ae --- /dev/null +++ b/css/pygments.css @@ -0,0 +1,59 @@ +.highlight .hll { background-color: #ffffcc } +.highlight .c { color: #999988; font-style: italic } /* Comment */ +.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ +.highlight .k { font-weight: bold } /* Keyword */ +.highlight .o { font-weight: bold } /* Operator */ +.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ +.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ +.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ +.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ +.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ +.highlight .ge { font-style: italic } /* Generic.Emph */ +.highlight .gr { color: #aa0000 } /* Generic.Error */ +.highlight .gh { color: #999999 } /* Generic.Heading */ +.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ +.highlight .go { color: #888888 } /* Generic.Output */ +.highlight .gp { color: #555555 } /* Generic.Prompt */ +.highlight .gs { font-weight: bold } /* Generic.Strong */ +.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ +.highlight .gt { color: #aa0000 } /* Generic.Traceback */ +.highlight .kc { font-weight: bold } /* Keyword.Constant */ +.highlight .kd { font-weight: bold } /* Keyword.Declaration */ +.highlight .kn { font-weight: bold } /* Keyword.Namespace */ +.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ +.highlight .kr { font-weight: bold } /* Keyword.Reserved */ +.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ +.highlight .m { color: #009999 } /* Literal.Number */ +.highlight .s { color: #bb8844 } /* Literal.String */ +.highlight .na { color: #008080 } /* Name.Attribute */ +.highlight .nb { color: #999999 } /* Name.Builtin */ +.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ +.highlight .no { color: #008080 } /* Name.Constant */ +.highlight .ni { color: #800080 } /* Name.Entity */ +.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ +.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ +.highlight .nn { color: #555555 } /* Name.Namespace */ +.highlight .nt { color: #000080 } /* Name.Tag */ +.highlight .nv { color: #008080 } /* Name.Variable */ +.highlight .ow { font-weight: bold } /* Operator.Word */ +.highlight .w { color: #bbbbbb } /* Text.Whitespace */ +.highlight .mf { color: #009999 } /* Literal.Number.Float */ +.highlight .mh { color: #009999 } /* Literal.Number.Hex */ +.highlight .mi { color: #009999 } /* Literal.Number.Integer */ +.highlight .mo { color: #009999 } /* Literal.Number.Oct */ +.highlight .sb { color: #bb8844 } /* Literal.String.Backtick */ +.highlight .sc { color: #bb8844 } /* Literal.String.Char */ +.highlight .sd { color: #bb8844 } /* Literal.String.Doc */ +.highlight .s2 { color: #bb8844 } /* Literal.String.Double */ +.highlight .se { color: #bb8844 } /* Literal.String.Escape */ +.highlight .sh { color: #bb8844 } /* Literal.String.Heredoc */ +.highlight .si { color: #bb8844 } /* Literal.String.Interpol */ +.highlight .sx { color: #bb8844 } /* Literal.String.Other */ +.highlight .sr { color: #808000 } /* Literal.String.Regex */ +.highlight .s1 { color: #bb8844 } /* Literal.String.Single */ +.highlight .ss { color: #bb8844 } /* Literal.String.Symbol */ +.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ +.highlight .vc { color: #008080 } /* Name.Variable.Class */ +.highlight .vg { color: #008080 } /* Name.Variable.Global */ +.highlight .vi { color: #008080 } /* Name.Variable.Instance */ +.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ diff --git a/style.css b/css/style.css similarity index 84% rename from style.css rename to css/style.css index 982fa08f57..99375ed2c4 100644 --- a/style.css +++ b/css/style.css @@ -8,7 +8,11 @@ body { } #content { - padding: 140px 110px 60px 110px; + padding: 0 110px 60px 110px; +} + +header { + padding: 140px 110px 0 110px; } h1 { @@ -53,7 +57,14 @@ h2 { margin-top: 80px; font-weight: 100; letter-spacing: 1px; + border-bottom: 1px solid #ddd; +} + +h3 { + font-weight: 200; + letter-spacing: 1px; border-bottom: 1px solid #eee; + margin-top: 40px; } #tag { @@ -80,7 +91,7 @@ h2 { margin-left: 170px; } -#tag + p { +#content > p:first-child { font-size: 22px; font-weight: 100; letter-spacing: 1px; @@ -130,17 +141,18 @@ code { } pre { - margin: 30px; - padding: 30px; - border: 1px solid #eee; - border-bottom-color: #ddd; - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - -o-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; + margin: 20px; + padding: 20px; + border: 1px solid #ddd; + border-bottom-color: #ccc; + background-color: #f3f3f3; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -o-border-radius: 3px; + border-radius: 3px; + -webkit-box-shadow: inset 0 0 10px #ddd; + -moz-box-shadow: inset 0 0 10px #ddd; + box-shadow: inset 0 0 10px #ddd; overflow-x: auto; } @@ -190,12 +202,6 @@ footer span { font-size: 12px; } -code .comment { color: #999 } -code .init { color: #2f6fad } -code .string { color: #5890ad } -code .keyword { color: #8a6343 } -code .number { color: #2f6fad } - @media all and (max-width: 850px) { ul li { width: 100%; @@ -213,3 +219,8 @@ code .number { color: #2f6fad } margin-left: 0; } } + +blockquote { + padding: 10px; + border-left: 1px solid #eee; +} diff --git a/foot.html b/foot.html deleted file mode 100644 index e2879ae7aa..0000000000 --- a/foot.html +++ /dev/null @@ -1,6 +0,0 @@ - -
    - © 2011 TJ Holowaychuk. All rights reserved. -
    - - \ No newline at end of file diff --git a/head.html b/head.html deleted file mode 100644 index c93fcfaee2..0000000000 --- a/head.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Mocha - the fun, simple, flexible JavaScript test framework - - - - - - - - - - -
    -

    Mocha

    -

    simple, flexible, fun

    diff --git a/highlight.js b/highlight.js deleted file mode 100644 index f6cddf60ba..0000000000 --- a/highlight.js +++ /dev/null @@ -1,18 +0,0 @@ - -$(function(){ - $('code').each(function(){ - $(this).html(highlight($(this).text())); - }); -}); - -function highlight(js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew *(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') -} \ No newline at end of file diff --git a/html5shiv.js b/html5shiv.js deleted file mode 100644 index 448cebd79e..0000000000 --- a/html5shiv.js +++ /dev/null @@ -1,8 +0,0 @@ -/* - HTML5 Shiv v3.7.0 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed -*/ -(function(l,f){function m(){var a=e.elements;return"string"==typeof a?a.split(" "):a}function i(a){var b=n[a[o]];b||(b={},h++,a[o]=h,n[h]=b);return b}function p(a,b,c){b||(b=f);if(g)return b.createElement(a);c||(c=i(b));b=c.cache[a]?c.cache[a].cloneNode():r.test(a)?(c.cache[a]=c.createElem(a)).cloneNode():c.createElem(a);return b.canHaveChildren&&!s.test(a)?c.frag.appendChild(b):b}function t(a,b){if(!b.cache)b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag(); -a.createElement=function(c){return!e.shivMethods?b.createElem(c):p(c,a,b)};a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+m().join().replace(/[\w\-]+/g,function(a){b.createElem(a);b.frag.createElement(a);return'c("'+a+'")'})+");return n}")(e,b.frag)}function q(a){a||(a=f);var b=i(a);if(e.shivCSS&&!j&&!b.hasCSS){var c,d=a;c=d.createElement("p");d=d.getElementsByTagName("head")[0]||d.documentElement;c.innerHTML="x"; -c=d.insertBefore(c.lastChild,d.firstChild);b.hasCSS=!!c}g||t(a,b);return a}var k=l.html5||{},s=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,r=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,j,o="_html5shiv",h=0,n={},g;(function(){try{var a=f.createElement("a");a.innerHTML="";j="hidden"in a;var b;if(!(b=1==a.childNodes.length)){f.createElement("a");var c=f.createDocumentFragment();b="undefined"==typeof c.cloneNode|| -"undefined"==typeof c.createDocumentFragment||"undefined"==typeof c.createElement}g=b}catch(d){g=j=!0}})();var e={elements:k.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output progress section summary template time video",version:"3.7.0",shivCSS:!1!==k.shivCSS,supportsUnknownElements:g,shivMethods:!1!==k.shivMethods,type:"default",shivDocument:q,createElement:p,createDocumentFragment:function(a,b){a||(a=f); -if(g)return a.createDocumentFragment();for(var b=b||i(a),c=b.frag.cloneNode(),d=0,e=m(),h=e.length;d - - - - Mocha - the fun, simple, flexible JavaScript test framework - - - - - - - - - - -
    -

    Mocha

    -

    simple, flexible, fun

    -

    Mocha is a feature-rich JavaScript test framework running on node.js and the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on GitHub.

    - -

    - -

    Features

    - -
      -
    • browser support
    • -
    • simple async support, including promises
    • -
    • test coverage reporting
    • -
    • string diff support
    • -
    • javascript API for running tests
    • -
    • proper exit status for CI support etc
    • -
    • auto-detects and disables coloring for non-ttys
    • -
    • maps uncaught exceptions to the correct test case
    • -
    • async test timeout support
    • -
    • test-specific timeouts
    • -
    • growl notification support
    • -
    • reports test durations
    • -
    • highlights slow tests
    • -
    • file watcher support
    • -
    • global variable leak detection
    • -
    • optionally run tests that match a regexp
    • -
    • auto-exit to prevent "hanging" with an active loop
    • -
    • easily meta-generate suites & test-cases
    • -
    • mocha.opts file support
    • -
    • clickable suite titles to filter test execution
    • -
    • node debugger support
    • -
    • detects multiple calls to done()
    • -
    • use any assertion library you want
    • -
    • extensible reporting, bundled with 9+ reporters
    • -
    • extensible test DSLs or "interfaces"
    • -
    • before, after, before each, after each hooks
    • -
    • arbitrary transpiler support (coffee-script etc)
    • -
    • TextMate bundle
    • -
    • and more!
    • -
    - -

    Table of contents

    - - - -

    Installation

    - -

    Install with npm:

    - -
    $ npm install -g mocha
    -
    - -

    1. 2. 3. Mocha!

    - -
    $ npm install -g mocha
    -$ mkdir test
    -$ $EDITOR test/test.js
    -
    -var assert = require("assert")
    -describe('Array', function(){
    -  describe('#indexOf()', function(){
    -    it('should return -1 when the value is not present', function(){
    -      assert.equal(-1, [1,2,3].indexOf(5));
    -      assert.equal(-1, [1,2,3].indexOf(0));
    -    })
    -  })
    -})
    -
    -$  mocha
    -
    -  .
    -
    -  ✔ 1 test complete (1ms)
    -
    - -

    Assertions

    - -

    Mocha allows you to use any assertion library you want, if it throws an error, it will work! This means you can utilize libraries such as should.js, node's regular assert module, or others. The following is a list of known assertion libraries for node and/or the browser:

    - -
      -
    • should.js BDD style shown throughout these docs
    • -
    • expect.js expect() style assertions
    • -
    • chai expect(), assert() and should style assertions
    • -
    • better-assert c-style self-documenting assert()
    • -
    - -

    Synchronous code

    - -

    When testing synchronous code, omit the callback and Mocha will automatically continue on to the next test.

    - -
    describe('Array', function(){
    -  describe('#indexOf()', function(){
    -    it('should return -1 when the value is not present', function(){
    -      [1,2,3].indexOf(5).should.equal(-1);
    -      [1,2,3].indexOf(0).should.equal(-1);
    -    })
    -  })
    -})
    -
    - -

    Asynchronous code

    - -

    Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named done) to it() Mocha will know that it should wait for completion.

    - -
    describe('User', function(){
    -  describe('#save()', function(){
    -    it('should save without error', function(done){
    -      var user = new User('Luna');
    -      user.save(function(err){
    -        if (err) throw err;
    -        done();
    -      });
    -    })
    -  })
    -})
    -
    - -

    To make things even easier, the done() callback accepts an error, so we may use this directly:

    - -
    describe('User', function(){
    -  describe('#save()', function(){
    -    it('should save without error', function(done){
    -      var user = new User('Luna');
    -      user.save(done);
    -    })
    -  })
    -})
    -
    - -

    All "hooks", that is before(), after(), beforeEach(), afterEach() may be sync or async as well, behaving much like a regular test-case. For example you may wish to populate database with dummy content before each test:

    - -
    describe('Connection', function(){
    -  var db = new Connection
    -    , tobi = new User('tobi')
    -    , loki = new User('loki')
    -    , jane = new User('jane');
    -
    -  beforeEach(function(done){
    -    db.clear(function(err){
    -      if (err) return done(err);
    -      db.save([tobi, loki, jane], done);
    -    });
    -  })
    -
    -  describe('#find()', function(){
    -    it('respond with matching records', function(done){
    -      db.find({ type: 'User' }, function(err, res){
    -        if (err) return done(err);
    -        res.should.have.length(3);
    -        done();
    -      })
    -    })
    -  })
    -})
    -
    - -

    Alternately, instead of using the done() callback, you can return a promise. This is useful if the APIs you are testing return promises instead of taking callbacks:

    - -
    beforeEach(function(){
    -  return db.clear().then(function() {
    -    return db.save([tobi, loki, jane]);
    -  });
    -})
    -
    -describe('#find()', function(){
    -  it('respond with matching records', function(){
    -    return db.find({ type: 'User' }).should.eventually.have.length(3);
    -  })
    -})
    -
    - -

    (The latter example uses Chai as Promised for fluent promise assertions.)

    - -

    Note that you may also pick any file and add "root" level hooks, for example add beforeEach() outside of describe()s then the callback will run before any test-case regardless of the file its in. This is because Mocha has a root Suite with no name.

    - -
    beforeEach(function(){
    -  console.log('before every test')
    -})
    -
    - -

    Hooks

    - -

    Mocha provides the hooks before(), after(), beforeEach(), afterEach(), - that can be used to set up preconditions and clean up your tests.

    - -
    describe('hooks', function() {
    -  before(function() {
    -    // runs before all tests in this block
    -  })
    -  after(function(){
    -    // runs after all tests in this block
    -  })
    -  beforeEach(function(){
    -    // runs before each test in this block
    -  })
    -  afterEach(function(){
    -    // runs after each test in this block
    -  })
    -  // test cases
    -})
    -
    - -

    All hooks can be invoked with an optional description, making it easier to pinpoint errors in your tests. - If hooks are given named functions those names will be used if no description is supplied.

    - -
    beforeEach(function(){
    -  // beforeEach hook
    -})
    -beforeEach(function namedFun() {
    -  // beforeEach:namedFun
    -})
    -beforeEach('some description', function(){
    -  // beforeEach:some description
    -})
    -
    - -

    Pending tests

    - -

    Pending test-cases are simply those without a callback:

    - -
    describe('Array', function(){
    -  describe('#indexOf()', function(){
    -    it('should return -1 when the value is not present')
    -  })
    -})
    -
    - -

    Exclusive tests

    - -

    The exclusivity feature allows you to run only the specified suite or test-case - by appending .only() to the call as shown here:

    - -
    describe('Array', function(){
    -  describe.only('#indexOf()', function(){
    -    ...
    -  })
    -})
    -
    - -

    Or a specific test-case:

    - -
    describe('Array', function(){
    -  describe('#indexOf()', function(){
    -    it.only('should return -1 unless present', function(){
    -
    -    })
    -
    -    it('should return the index when present', function(){
    -
    -    })
    -  })
    -})
    -
    - -

    Note that currently only one .only() call is respected, this - effectively turns into a --grep.

    - -

    Inclusive tests

    - -

    This feature is similar to .only(), however by appending .skip() - you may tell Mocha to simply ignore these suite(s) and test-case(s). This - puts them in a pending state, and is favoured over commenting out tests - which you may forget to uncomment.

    - -
    describe('Array', function(){
    -  describe.skip('#indexOf()', function(){
    -    ...
    -  })
    -})
    -
    - -

    Or a specific test-case:

    - -
    describe('Array', function(){
    -  describe('#indexOf()', function(){
    -    it.skip('should return -1 unless present', function(){
    -
    -    })
    -
    -    it('should return the index when present', function(){
    -
    -    })
    -  })
    -})
    -
    - -

    Meta-Generated tests

    - -

    Given mocha's use of call statements and function expressions to define - suites and specs, it's rather straightforward to generate your tests. No - special syntax is required - plain JavaScript can be used to achieve - similar functionality as parameterized tests in other test frameworks. - Take the following example:

    - -
    var assert = require('assert');
    -
    -function add() {
    -  return Array.prototype.slice.call(arguments).reduce(function(prev, curr) {
    -    return prev + curr;
    -  }, 0);
    -}
    -
    -describe('add()', function() {
    -  var tests = [
    -    {args: [1, 2],       expected: 3},
    -    {args: [1, 2, 3],    expected: 6},
    -    {args: [1, 2, 3, 4], expected: 10}
    -  ];
    -
    -  tests.forEach(function(test) {
    -    it('correctly adds ' + test.args.length + ' args', function() {
    -      var res = add.apply(null, test.args);
    -      assert.equal(res, test.expected);
    -    });
    -  });
    -});
    -
    - -

    The code above will output a suite with three specs:

    - -
    add()
    -  ✓ correctly adds 2 args
    -  ✓ correctly adds 3 args
    -  ✓ correctly adds 4 args
    -
    - -

    Test duration

    - -

    Most of the reporters support some form of displaying - test duration, as well as flagging tests that are slow, - as shown here with the "spec" reporter:

    - -

    test duration

    - -

    String diffs

    - -

    Mocha supports the err.expected, and err.actual properties - when available to present expectations to the developer. Currently - Mocha provides string diffs, however in the future object diffs and - others may be provided.

    - -

    string diffs

    - -

    mocha(1)

    - -
    Usage: mocha [debug] [options] [files]
    -
    -Commands:
    -
    -  init <path>
    -  initialize a client-side mocha setup at <path>
    -
    -Options:
    -
    - -h, --help                              output usage information
    - -V, --version                           output the version number
    - -A, --async-only                        force all tests to take a callback (async)
    - -c, --colors                            force enabling of colors
    - -C, --no-colors                         force disabling of colors
    - -G, --growl                             enable growl notification support
    - -O, --reporter-options <k=v,k2=v2,...>  reporter-specific options
    - -R, --reporter <name>                   specify the reporter to use
    - -S, --sort                              sort test files
    - -b, --bail                              bail after first test failure
    - -d, --debug                             enable node's debugger, synonym for node --debug
    - -g, --grep <pattern>                    only run tests matching <pattern>
    - -f, --fgrep <string>                    only run tests containing <string>
    - -gc, --expose-gc                        expose gc extension
    - -i, --invert                            inverts --grep and --fgrep matches
    - -r, --require <name>                    require the given module
    - -s, --slow <ms>                         "slow" test threshold in milliseconds [75]
    - -t, --timeout <ms>                      set test-case timeout in milliseconds [2000]
    - -u, --ui <name>                         specify user-interface (bdd|tdd|exports)
    - -w, --watch                             watch files for changes
    - --check-leaks                           check for global variable leaks
    - --compilers <ext>:<module>,...          use the given module(s) to compile files
    - --debug-brk                             enable node's debugger breaking on the first line
    - --globals <names>                       allow the given comma-delimited global [names]
    - --inline-diffs                          display actual/expected differences inline within each string
    - --interfaces                            display available interfaces
    - --no-deprecation                        silence deprecation warnings
    - --no-exit                               require a clean shutdown of the event loop: mocha will exit
    - --no-timeouts                           disables timeouts, given implicitly with --debug
    - --opts <path>                           specify opts path
    - --prof                                  log statistical profiling information
    - --recursive                             include sub directories
    - --reporters                             display available reporters
    - --throw-deprecation                     throw an exception anytime a deprecated function is used
    - --trace                                 trace function calls
    - --trace-deprecation                     show stack traces on deprecations
    - --watch-extensions <ext>,...            additional extensions to monitor with --watch
    - --delay                                 wait for async suite definition
    -
    - -

    -w, --watch

    - -

    Executes tests on changes to JavaScript in the CWD, and once initially.

    - -

    --compilers

    - -

    coffee-script is no longer supported out of the box. CS and similar transpilers - may be used by mapping the file extensions (for use with --watch) and the module - name. For example --compilers coffee:coffee-script with CoffeeScript 1.6- or - --compilers coffee:coffee-script/register with CoffeeScript 1.7+.

    - -

    -b, --bail

    - -

    Only interested in the first exception? use --bail !

    - -

    -d, --debug

    - -

    Enables node's debugger support, this executes your script(s) with node debug <file ...> allowing you to step through code and break with the debugger statement. Note the difference between mocha debug and mocha --debug: mocha debug will fire up node's built-in debug client, mocha --debug will allow you to use a different interface — such as the Blink Developer Tools.

    - -

    --globals <names>

    - -

    Accepts a comma-delimited list of accepted global variable names. For example, suppose your app deliberately exposes a global named app and YUI, you may want to add --globals app,YUI. It also accepts wildcards. You could do --globals '*bar' and it would match foobar, barbar, etc. You can also simply pass in '*' to ignore all globals.

    - -

    --check-leaks

    - -

    By default Mocha will not check for global variables leaked while running tests, to enable this pass --check-leaks, to specify globals that are acceptable use --globals, for example --globals jQuery,MyLib.

    - -

    -r, --require <name>

    - -

    The --require option is useful for libraries such as should.js, so you may simply --require should instead of manually invoking require('should') within each test file. Note that this works well for should as it augments Object.prototype, however if you wish to access a module's exports you will have to require them, for example var should = require('should'). Furthermore, it can be used with relative paths, e.g. --require ./test/helper.js

    - -

    -u, --ui <name>

    - -

    The --ui option lets you specify the interface to use, defaulting to "bdd".

    - -

    -R, --reporter <name>

    - -

    The --reporter option allows you to specify the reporter that will be used, defaulting to "dot". This flag may also be used to utilize third-party reporters. For example if you npm install mocha-lcov-reporter you may then do --reporter mocha-lcov-reporter.

    - -

    -t, --timeout <ms>

    - -

    Specifies the test-case timeout, defaulting to 2 seconds. To override you may pass the timeout in milliseconds, or a value with the s suffix, ex: --timeout 2s or --timeout 2000 would be equivalent.

    - -

    -s, --slow <ms>

    - -

    Specify the "slow" test threshold, defaulting to 75ms. Mocha uses this to highlight test-cases that are taking too long.

    - -

    -g, --grep <pattern>

    - -

    The --grep option when specified will trigger mocha to only run tests matching the given pattern which is internally compiled to a RegExp.

    - -

    Suppose for example you have "api" related tests, as well as "app" related tests, as shown in the following snippet; One could use --grep api or --grep app to run one or the other. The same goes for any other part of a suite or test-case title, --grep users would be valid as well, or even --grep GET.

    - -
    describe('api', function(){
    -  describe('GET /api/users', function(){
    -    it('respond with an array of users')
    -  })
    -})
    -
    -describe('app', function(){
    -  describe('GET /users', function(){
    -    it('respond with an array of users')
    -  })
    -})
    -
    - -

    Interfaces

    - -

    Mocha "interface" system allows developers to choose their style of DSL. Shipping with BDD, TDD, and exports flavoured interfaces.

    - -

    BDD

    - -

    The "BDD" interface provides describe(), context(), it(), before(), after(), beforeEach(), and afterEach():

    - -

    context() is just an alias for describe(), and behaves the same way; it just provides a way to keep tests easier to read and organized.

    - -
    describe('Array', function(){
    -  before(function(){
    -    // ...
    -  });
    -
    -  describe('#indexOf()', function(){
    -    context('when not present', function(){
    -      it('should not throw an error', function(){
    -        (function(){
    -          [1,2,3].indexOf(4);
    -        }).should.not.throw();
    -      });
    -      it('should return -1', function(){
    -        [1,2,3].indexOf(4).should.equal(-1);
    -      });
    -    });
    -    context('when present', function(){
    -      it('should return the index where the element first appears in the array', function(){
    -        [1,2,3].indexOf(3).should.equal(2);
    -      });
    -    });
    -  });
    -});
    -
    - -

    TDD

    - -

    The "TDD" interface provides suite(), test(), suiteSetup(), suiteTeardown(), setup(), and teardown().

    - -
    suite('Array', function(){
    -  setup(function(){
    -    // ...
    -  });
    -
    -  suite('#indexOf()', function(){
    -    test('should return -1 when not present', function(){
    -      assert.equal(-1, [1,2,3].indexOf(4));
    -    });
    -  });
    -});
    -
    - -

    Exports

    - -

    The "exports" interface is much like Mocha's predecessor expresso. The keys before, after, beforeEach, and afterEach are special-cased, object values - are suites, and function values are test-cases.

    - -
    module.exports = {
    -  before: function(){
    -    // ...
    -  },
    -
    -  'Array': {
    -    '#indexOf()': {
    -      'should return -1 when not present': function(){
    -        [1,2,3].indexOf(4).should.equal(-1);
    -      }
    -    }
    -  }
    -};
    -
    - -

    QUnit

    - -

    The qunit-inspired interface matches the "flat" look of QUnit where the test suite title is simply defined before the test-cases. Like TDD, it uses suite() and test(), but resembling BDD it also contains before(), after(), beforeEach(), and afterEach().

    - -
    function ok(expr, msg) {
    -  if (!expr) throw new Error(msg);
    -}
    -
    -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);
    -});
    -
    - -

    Require

    - -

    The require interface allows you to require the describe and friend words - directly using require and call them whatever you want. This interface - is also useful if you want to avoid global variables in your tests.

    - -

    Note this works when you run your tests via the mocha executable only, and not when using the node executable directly. The reason is that - certain methods are exposed at runtime and when using the mocha executable only.

    - -
    var testCase = require('mocha').describe
    -var pre = require('mocha').before
    -var assertions = require('mocha').it
    -var assert = require('assert')
    -
    -testCase('Array', function(){
    -  pre(function(){
    -    // ...
    -  });
    -
    -  testCase('#indexOf()', function(){
    -    assertions('should return -1 when not present', function(){
    -      assert.equal([1,2,3].indexOf(4), -1);
    -    });
    -  });
    -});
    -
    - -

    Reporters

    - -

    Mocha reporters adjust to the terminal window, - and always disable ansi-escape colouring when - the stdio streams are not associated with a tty.

    - -

    Dot Matrix

    - -

    The "dot" matrix reporter is simply a series of dots - that represent test cases, failures highlight in red, - pending in blue, slow as yellow.

    - -

    dot matrix reporter

    - -

    Spec

    - -

    The "spec" reporter outputs a hierarchical view - nested just as the test cases are.

    - -

    spec reporter - spec reporter with failure

    - -

    Nyan

    - -

    The "nyan" reporter is exactly what you might expect:

    - -

    js nyan cat reporter

    - -

    TAP

    - -

    The TAP reporter emits lines for a Test-Anything-Protocol consumer.

    - -

    test anything protocol

    - -

    Landing Strip

    - -

    The Landing Strip reporter is a gimmicky test reporter simulating - a plane landing :) unicode ftw

    - -

    landing strip plane reporter - landing strip with failure

    - -

    List

    - -

    The "List" reporter outputs a simple specifications list as - test cases pass or fail, outputting the failure details at - the bottom of the output.

    - -

    list reporter

    - -

    Progress

    - -

    The progress reporter implements a simple progress-bar:

    - -

    progress bar

    - -

    JSON

    - -

    The JSON reporter outputs a single large JSON object when - the tests have completed (failures or not).

    - -

    json reporter

    - -

    JSON Stream

    - -

    The JSON Stream reporter outputs newline-delimited JSON "events" as they occur, beginning with a "start" event, followed by test passes or failures, and then the final "end" event.

    - -

    json stream reporter

    - -

    JSONCov

    - -

    The JSONCov reporter is similar to the JSON reporter, however when run against a library instrumented by node-jscoverage it will produce coverage output.

    - -

    HTMLCov

    - -

    The HTMLCov reporter extends the JSONCov reporter. The library being tested should first be instrumented by node-jscoverage, this allows Mocha to capture the coverage information necessary to produce a single-page HTML report.

    - -

    Click to view the current Express test coverage report. For an integration example view the mocha test coverage support commit for Express.

    - -

    code coverage reporting

    - -

    Min

    - -

    The "min" reporter displays the summary only, while still outputting errors - on failure. This reporter works great with --watch as it clears the terminal - in order to keep your test summary at the top.

    - -

    min reporter

    - -

    Doc

    - -

    The "doc" reporter outputs a hierarchical HTML body representation - of your tests, wrap it with a header, footer, some styling and you - have some fantastic documentation!

    - -

    doc reporter

    - -

    For example suppose you have the following JavaScript:

    - -
    describe('Array', function(){
    -  describe('#indexOf()', function(){
    -    it('should return -1 when the value is not present', function(){
    -      [1,2,3].indexOf(5).should.equal(-1);
    -      [1,2,3].indexOf(0).should.equal(-1);
    -    })
    -  })
    -})
    -
    - -

    The command mocha --reporter doc array would yield:

    - -
    <section class="suite">
    -  <h1>Array</h1>
    -  <dl>
    -    <section class="suite">
    -      <h1>#indexOf()</h1>
    -      <dl>
    -      <dt>should return -1 when the value is not present</dt>
    -      <dd><pre><code>[1,2,3].indexOf(5).should.equal(-1);
    -[1,2,3].indexOf(0).should.equal(-1);</code></pre></dd>
    -      </dl>
    -    </section>
    -  </dl>
    -</section>
    -
    - -

    The SuperAgent request library test documentation was generated with Mocha's doc reporter using this simple make target:

    - -
    test-docs:
    -    make test REPORTER=doc \
    -        | cat docs/head.html - docs/tail.html \
    -        > docs/test.html
    -
    - -

    View the entire Makefile for reference.

    - -

    XUnit

    - -

    Documentation needed.

    - -

    TeamCity

    - -

    Documentation needed.

    - -

    Markdown

    - -

    The "markdown" reporter generates a markdown TOC and body for your - test suite. This is great if you want to use the tests as documentation - within a Github wiki page, or a markdown file in the repository that - Github can render. For example here is the Connect test output.

    - -

    HTML

    - -

    The HTML reporter is currently the only browser reporter - supported by Mocha, and it looks like this:

    - -

    HTML test reporter

    - -

    Browser support

    - -

    Mocha runs in the browser. Every release of Mocha will have new builds of ./mocha.js and ./mocha.css for use in the browser. To setup Mocha for browser use all you have to do is include the script, stylesheet, tell Mocha which interface you wish to use, and then run the tests. A typical setup might look something like the following, where we call mocha.setup('bdd') to use the BDD interface before loading the test scripts, running them onload with mocha.run().

    - -
    <html>
    -<head>
    -  <meta charset="utf-8">
    -  <title>Mocha Tests</title>
    -  <link rel="stylesheet" href="mocha.css" />
    -</head>
    -<body>
    -  <div id="mocha"></div>
    -  <script src="jquery.js"></script>
    -  <script src="expect.js"></script>
    -  <script src="mocha.js"></script>
    -  <script>mocha.setup('bdd')</script>
    -  <script src="test.array.js"></script>
    -  <script src="test.object.js"></script>
    -  <script src="test.xhr.js"></script>
    -  <script>
    -    mocha.checkLeaks();
    -    mocha.globals(['jQuery']);
    -    mocha.run();
    -  </script>
    -</body>
    -</html>
    -
    - -

    grep

    - -

    The client-side may use --grep as well, however, you must append a query-string to your URL: ?grep=api.

    - -

    Mocha Setup in the Browser

    - -

    Mocha options can be set via mocha.setup(). Examples:

    - -
    // Use "tdd" interface.  This is a shortcut to setting the interface;
    -// any other options must be passed via an object.
    -mocha.setup('tdd');
    -
    -// This is equivalent to the above.
    -mocha.setup({
    -  ui: 'tdd'
    -});
    -
    -// Use "tdd" interface, ignore leaks, and force all tests to be asynchronous
    -mocha.setup({
    -  ui: 'tdd',
    -  ignoreLeaks: true,
    -  asyncOnly: true
    -});
    -
    - -

    Browser-specific option(s)

    - -

    The following option(s) only function in a browser context:

    - -

    noHighlighting : If set to true, do not attempt to use syntax highlighting on output test code.

    - -

    mocha.opts

    - -

    Mocha will attempt to load ./test/mocha.opts, these are concatenated with process.argv, though command-line args will take precedence. For example suppose you have the following mocha.opts file:

    - -
    --require should
    ---reporter dot
    ---ui bdd
    -
    - -

    This will default the reporter to dot, require the should library, - and use bdd as the interface. With this you may then invoke mocha(1) - with additional arguments, here enabling growl support and changing - the reporter to list:

    - -
    $ mocha --reporter list --growl
    -
    - -

    Suite specific timeouts

    - -

    Suite-level timeouts may be applied to entire test "suites", or disabled - via this.timeout(0). This will be inherited by all nested suites and test-cases - that do not override the value.

    - -
    describe('a suite of tests', function(){
    -  this.timeout(500);
    -
    -  it('should take less than 500ms', function(done){
    -    setTimeout(done, 300);
    -  })
    -
    -  it('should take less than 500ms as well', function(done){
    -    setTimeout(done, 200);
    -  })
    -})
    -
    - -

    Test specific timeouts

    - -

    Test-specific timeouts may also be applied, or the use of this.timeout(0) - to disable timeouts all together:

    - -
    it('should take less than 500ms', function(done){
    -  this.timeout(500);
    -  setTimeout(done, 300);
    -})
    -
    - -

    Best practices

    - -

    test/*

    - -

    By default mocha(1) will use the pattern ./test/*.js, so - it's usually a good place to put your tests.

    - -

    Makefiles

    - -

    Be kind and don't make developers hunt around in your docs to figure - out how to run the tests, add a make test target to your Makefile:

    - -
    test:
    -    ./node_modules/.bin/mocha --reporter list
    -
    -.PHONY: test
    -
    - -

    Editors

    - -

    The following editor-related packages are available:

    - -

    TextMate bundle

    - -

    The Mocha TextMate bundle includes snippets to - make writing tests quicker and more enjoyable. - To install the bundle run:

    - -
    $ make tm
    -
    - -

    JetBrains plugin

    - -

    JetBrains provides a NodeJS plugin for its suite of IDEs (IntelliJ IDEA, WebStorm, etc.), which contains a Mocha test runner, among other things.

    - -

    JetBrains Mocha Runner Plugin in Action

    - -

    The plugin is titled NodeJS, and can be installed via Preferences > Plugins, or via direct download.

    - -

    Example test suites

    - -

    The following test suites are from real projects putting Mocha to use, - so they serve as good examples:

    - - - -

    Running mocha's tests

    - -

    Run the tests:

    - -
    $ make test
    -
    - -

    Run all tests, including interfaces:

    - -
    $ make test-all
    -
    - -

    Alter the reporter:

    - -
    $ make test REPORTER=list
    -
    - -

    More information

    - -

    For additional information such as using spies, mocking, and shared behaviours be sure to check out the Mocha Wiki on GitHub. For discussions join the Google Group. For a running example of mocha view example/tests.html. For the JavaScript API view the source.

    -
    -
    - © 2011 TJ Holowaychuk. All rights reserved. -
    - - \ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index 238f0f16cd..0000000000 --- a/index.js +++ /dev/null @@ -1,2 +0,0 @@ - -module.exports = require('./lib/mocha'); \ No newline at end of file diff --git a/index.md b/index.md index 136bde0856..ab4c296ee4 100644 --- a/index.md +++ b/index.md @@ -1,908 +1,1045 @@ -Mocha is a feature-rich JavaScript test framework running on [node.js](http://nodejs.org) and the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on [GitHub](https://github.com/mochajs/mocha). - - - -

    Features

    - - - browser support - - simple async support, including promises - - test coverage reporting - - string diff support - - javascript API for running tests - - proper exit status for CI support etc - - auto-detects and disables coloring for non-ttys - - maps uncaught exceptions to the correct test case - - async test timeout support - - test-specific timeouts - - growl notification support - - reports test durations - - highlights slow tests - - file watcher support - - global variable leak detection - - optionally run tests that match a regexp - - auto-exit to prevent "hanging" with an active loop - - easily meta-generate suites & test-cases - - mocha.opts file support - - clickable suite titles to filter test execution - - node debugger support - - detects multiple calls to `done()` - - use any assertion library you want - - extensible reporting, bundled with 9+ reporters - - extensible test DSLs or "interfaces" - - before, after, before each, after each hooks - - arbitrary transpiler support (coffee-script etc) - - TextMate bundle - - and more! - -

    Table of contents

    - - - [Installation](#installation) - - [1\. 2\. 3\. Mocha!](#getting-started) - - [Assertions](#assertions) - - [Synchronous code](#synchronous-code) - - [Asynchronous code](#asynchronous-code) - - [Hooks](#hooks) - - [Pending tests](#pending-tests) - - [Exclusive tests](#exclusive-tests) - - [Inclusive tests](#inclusive-tests) - - [Meta-Generated tests](#meta-generated-test) - - [Test duration](#test-duration) - - [String diffs](#string-diffs) - - [mocha(1)](#usage) - - [Interfaces](#interfaces) - - [Reporters](#reporters) - - [Browser support](#browser-support) - - [mocha.opts](#mocha.opts) - - [Suite specific timeouts](#suite-specific-timeouts) - - [Test specific timeouts](#test-specific-timeouts) - - [Best practices](#best-practices) - - [Editors](#editors) - - [Example test suites](#example-test-suites) - - [Running mocha's tests](#running-mochas-tests) - - [More information](#more-information) - -

    Installation

    - - Install with [npm](http://npmjs.org): - - $ npm install -g mocha - -

    1. 2. 3. Mocha!

    - - - $ npm install -g mocha - $ mkdir test - $ $EDITOR test/test.js - - var assert = require("assert") - describe('Array', function(){ - describe('#indexOf()', function(){ - it('should return -1 when the value is not present', function(){ - assert.equal(-1, [1,2,3].indexOf(5)); - assert.equal(-1, [1,2,3].indexOf(0)); - }) - }) - }) - - $ mocha - - . - - ✔ 1 test complete (1ms) - - -

    Assertions

    - -Mocha allows you to use any assertion library you want, if it throws an error, it will work! This means you can utilize libraries such as [should.js](https://github.com/visionmedia/should.js), node's regular `assert` module, or others. The following is a list of known assertion libraries for node and/or the browser: - - - [should.js](https://github.com/visionmedia/should.js) BDD style shown throughout these docs - - [expect.js](https://github.com/LearnBoost/expect.js) expect() style assertions - - [chai](http://chaijs.com/) expect(), assert() and should style assertions - - [better-assert](https://github.com/visionmedia/better-assert) c-style self-documenting assert() - -

    Synchronous code

    - - When testing synchronous code, omit the callback and Mocha will automatically continue on to the next test. +--- +layout: default +--- +Mocha is a feature-rich JavaScript test framework running on [Node.js](http://nodejs.org) and the browser, making asynchronous testing simple and fun. Mocha tests run serially, allowing for flexible and accurate reporting, while mapping uncaught exceptions to the correct test cases. Hosted on [GitHub](https://github.com/mochajs/mocha). + +[![Gitter](//badges.gitter.im/Join%20Chat.svg)](https://gitter.im/mochajs/mocha) + +## Features + +- browser support +- simple async support, including promises +- test coverage reporting +- string diff support +- javascript API for running tests +- proper exit status for CI support etc +- auto-detects and disables coloring for non-ttys +- maps uncaught exceptions to the correct test case +- async test timeout support +- test-specific timeouts +- growl notification support +- reports test durations +- highlights slow tests +- file watcher support +- global variable leak detection +- optionally run tests that match a regexp +- auto-exit to prevent "hanging" with an active loop +- easily meta-generate suites & test-cases +- mocha.opts file support +- clickable suite titles to filter test execution +- node debugger support +- detects multiple calls to `done()` +- use any assertion library you want +- extensible reporting, bundled with 9+ reporters +- extensible test DSLs or "interfaces" +- before, after, before each, after each hooks +- arbitrary transpiler support (coffee-script etc) +- TextMate bundle +- and more! + +## Table of Contents + + + +* [Features](#features) +* [Installation](#installation) +* [Getting Started](#getting-started) +* [Assertions](#assertions) +* [Synchronous Code](#synchronous-code) +* [Asynchronous Code](#asynchronous-code) + * [Working with Promises](#working-with-promises) +* [Hooks](#hooks) + * [Describing Hooks](#describing-hooks) + * [Asynchronous Hooks](#asynchronous-hooks) + * [Root-Level Hooks](#root-level-hooks) + * [Delayed Root Suite](#delayed-root-suite) +* [Pending Tests](#pending-tests) +* [Exclusive Tests](#exclusive-tests) +* [Inclusive Tests](#inclusive-tests) +* [Dynamically Generating Tests](#dynamically-generating-tests) +* [Timeouts](#timeouts) + * [Suite-level](#suite-level) + * [Test-level](#test-level) +* [Diffs](#diffs) +* [Usage](#usage) + * [`-w, --watch`](#-w-watch) + * [`--compilers`](#-compilers) + * [`-b, --bail`](#-b-bail) + * [`-d, --debug`](#-d-debug) + * [`--globals `](#-globals-names) + * [`--check-leaks`](#-check-leaks) + * [`-r, --require `](#-r-require-module-name) + * [`-u, --ui `](#-u-ui-name) + * [`-R, --reporter `](#-r-reporter-name) + * [`-t, --timeout `](#-t-timeout-ms) + * [`-s, --slow `](#-s-slow-ms) + * [`-g, --grep `](#-g-grep-pattern) +* [Interfaces](#interfaces) + * [BDD](#bdd) + * [TDD](#tdd) + * [Exports](#exports) + * [QUnit](#qunit) + * [Require](#require) +* [Reporters](#reporters) + * [Spec](#spec) + * [Dot Matrix](#dot-matrix) + * [Nyan](#nyan) + * [TAP](#tap) + * [Landing Strip](#landing-strip) + * [List](#list) + * [Progress](#progress) + * [JSON](#json) + * [JSON Stream](#json-stream) + * [JSONCov](#jsoncov) + * [HTMLCov](#htmlcov) + * [Min](#min) + * [Doc](#doc) + * [Markdown](#markdown) + * [HTML](#html) + * [Undocumented Reporters](#undocumented-reporters) +* [Running Mocha in the Browser](#running-mocha-in-the-browser) + * [Grep](#grep) + * [Browser Configuration](#browser-configuration) + * [Browser-specific Option(s)](#browser-specific-options) +* [`mocha.opts`](#mochaopts) +* [The `test/` Directory](#the-test-directory) +* [Editor Plugins](#editor-plugins) + * [TextMate](#textmate) + * [JetBrains](#jetbrains) +* [Examples](#examples) +* [Testing Mocha](#testing-mocha) +* [More Information](#more-information) + + + + +## Installation + +Install with [npm](http://npmjs.org): + +```sh +$ npm install -g mocha +``` + +## Getting Started + +```sh +$ npm install -g mocha +$ mkdir test +$ $EDITOR test/test.js + +``` + +In your editor: + +```js +var assert = require("assert") +describe('Array', function() { + describe('#indexOf()', function () { + it('should return -1 when the value is not present', function () { + assert.equal(-1, [1,2,3].indexOf(5)); + assert.equal(-1, [1,2,3].indexOf(0)); + }); + }); +}); +``` - describe('Array', function(){ - describe('#indexOf()', function(){ - it('should return -1 when the value is not present', function(){ - [1,2,3].indexOf(5).should.equal(-1); - [1,2,3].indexOf(0).should.equal(-1); - }) - }) - }) +Back in the terminal: -

    Asynchronous code

    +```sh +$ mocha -Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named `done`) to `it()` Mocha will know that it should wait for completion. + . - describe('User', function(){ - describe('#save()', function(){ - it('should save without error', function(done){ - var user = new User('Luna'); - user.save(function(err){ - if (err) throw err; - done(); - }); - }) - }) - }) - - To make things even easier, the `done()` callback accepts an error, so we may use this directly: - - describe('User', function(){ - describe('#save()', function(){ - it('should save without error', function(done){ - var user = new User('Luna'); - user.save(done); - }) - }) - }) - - All "hooks", that is `before()`, `after()`, `beforeEach()`, `afterEach()` may be sync or async as well, behaving much like a regular test-case. For example you may wish to populate database with dummy content before each test: - - describe('Connection', function(){ - var db = new Connection - , tobi = new User('tobi') - , loki = new User('loki') - , jane = new User('jane'); - - beforeEach(function(done){ - db.clear(function(err){ - if (err) return done(err); - db.save([tobi, loki, jane], done); - }); - }) - - describe('#find()', function(){ - it('respond with matching records', function(done){ - db.find({ type: 'User' }, function(err, res){ - if (err) return done(err); - res.should.have.length(3); - done(); - }) - }) - }) - }) - - Alternately, instead of using the `done()` callback, you can return a promise. This is useful if the APIs you are testing return promises instead of taking callbacks: - - beforeEach(function(){ - return db.clear().then(function() { - return db.save([tobi, loki, jane]); - }); - }) + ✔ 1 test complete (1ms) +``` - describe('#find()', function(){ - it('respond with matching records', function(){ - return db.find({ type: 'User' }).should.eventually.have.length(3); - }) - }) +## Assertions - (The latter example uses [Chai as Promised](https://github.com/domenic/chai-as-promised/) for fluent promise assertions.) - - Note that you may also pick any file and add "root" level hooks, for example add `beforeEach()` outside of `describe()`s then the callback will run before any test-case regardless of the file its in. This is because Mocha has a root `Suite` with no name. - - beforeEach(function(){ - console.log('before every test') - }) +Mocha allows you to use any assertion library you want, if it throws an error, it will work! This means you can utilize libraries such as [should.js](https://github.com/visionmedia/should.js), node's regular `assert` module, or others. The following is a list of known assertion libraries for node and/or the browser: -

    Hooks

    +- [should.js](https://github.com/visionmedia/should.js) BDD style shown throughout these docs +- [expect.js](https://github.com/LearnBoost/expect.js) expect() style assertions +- [chai](http://chaijs.com/) expect(), assert() and should style assertions +- [better-assert](https://github.com/visionmedia/better-assert) c-style self-documenting assert() - Mocha provides the hooks `before()`, `after()`, `beforeEach()`, `afterEach()`, - that can be used to set up preconditions and clean up your tests. +## Synchronous Code - describe('hooks', function() { - before(function() { - // runs before all tests in this block - }) - after(function(){ - // runs after all tests in this block - }) - beforeEach(function(){ - // runs before each test in this block - }) - afterEach(function(){ - // runs after each test in this block - }) - // test cases - }) +When testing synchronous code, omit the callback and Mocha will automatically continue on to the next test. +```js +describe('Array', function() { + describe('#indexOf()', function() { + it('should return -1 when the value is not present', function() { + [1,2,3].indexOf(5).should.equal(-1); + [1,2,3].indexOf(0).should.equal(-1); + }); + }); +}); +``` +## Asynchronous Code - All hooks can be invoked with an optional description, making it easier to pinpoint errors in your tests. - If hooks are given named functions those names will be used if no description is supplied. +Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named `done`) to `it()` Mocha will know that it should wait for completion. - beforeEach(function(){ - // beforeEach hook - }) - beforeEach(function namedFun() { - // beforeEach:namedFun - }) - beforeEach('some description', function(){ - // beforeEach:some description - }) +```js +describe('User', function() { + describe('#save()', function() { + it('should save without error', function(done) { + var user = new User('Luna'); + user.save(function(err) { + if (err) throw err; + done(); + }); + }); + }); +}); +``` + +To make things even easier, the `done()` callback accepts an error, so we may use this directly: + +```js +describe('User', function() { + describe('#save()', function() { + it('should save without error', function(done) { + var user = new User('Luna'); + user.save(done); + }); + }); +}); +``` +### Working with Promises +Alternately, instead of using the `done()` callback, you may return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise). This is useful if the APIs you are testing return promises instead of taking callbacks: -

    Pending tests

    +```js +beforeEach(function() { + return db.clear() + .then(function() { + return db.save([tobi, loki, jane]); + }); +}); + +describe('#find()', function() { + it('respond with matching records', function() { + return db.find({ type: 'User' }).should.eventually.have.length(3); + }); +}); +``` + +(The latter example uses [Chai as Promised](https://www.npmjs.com/package/chai-as-promised) for fluent promise assertions.) + +## Hooks + +Mocha provides the hooks `before()`, `after()`, `beforeEach()`, and `afterEach()`, which can be used to set up preconditions and clean up after your tests. + +```js +describe('hooks', function() { + + before(function() { + // runs before all tests in this block + }); + + after(function() { + // runs after all tests in this block + }); + + beforeEach(function() { + // runs before each test in this block + }); + + afterEach(function() { + // runs after each test in this block + }); + + // test cases +}); +``` + +### Describing Hooks + +All hooks can be invoked with an optional description, making it easier to pinpoint errors in your tests. If hooks are given named functions, those names will be used if no description is supplied. + +```js +beforeEach(function() { + // beforeEach hook +}); + +beforeEach(function namedFun() { + // beforeEach:namedFun +}); + +beforeEach('some description', function() { + // beforeEach:some description +}); +``` + +### Asynchronous Hooks + +All "hooks" (`before()`, `after()`, `beforeEach()`, `afterEach()`) may be sync or async as well, behaving much like a regular test-case. For example, you may wish to populate database with dummy content before each test: + +```js +describe('Connection', function() { + var db = new Connection, + tobi = new User('tobi'), + loki = new User('loki'), + jane = new User('jane'); + + beforeEach(function(done) { + db.clear(function(err) { + if (err) return done(err); + db.save([tobi, loki, jane], done); + }); + }); + + describe('#find()', function() { + it('respond with matching records', function(done) { + db.find({type: 'User'}, function(err, res) { + if (err) return done(err); + res.should.have.length(3); + done(); + }); + }); + }); +}); +``` + + +### Root-Level Hooks + +You may also pick any file and add "root"-level hooks. For example, add `beforeEach()` outside of all `describe()` blocks. This will cause the callback to `beforeEach()` to run before any test case, regardless of the file it lives in (this is because Mocha has a hidden `describe()` block, called the "root suite"). + +```js +beforeEach(function() { + console.log('before every test in every file'); +}); +``` + +### Delayed Root Suite + +If you need to perform asynchronous operations before any of your suites are run, you may delay the root suite. Simply run Mocha with the `--delay` flag. This will provide a special function, `run()`, in the global context. + +```js +setTimeout(function() { + // do some setup + + describe('my suite', function() { + // ... + }); + + run(); +}, 5000); +``` + +## Pending Tests + +"Pending"--as in "someone should write these test cases eventually"--test-cases are simply those without a callback: + +```js +describe('Array', function() { + describe('#indexOf()', function() { + // pending test below + it('should return -1 when the value is not present'); + }); +}); +``` + +Pending tests will be reported as such. + +## Exclusive Tests + +The exclusivity feature allows you to run *only* the specified suite or test-case + by appending `.only()` to the function. Here's an example of executing only a particular suite: + +```js +describe('Array', function() { + describe.only('#indexOf()', function() { + // ... + }); +}); +``` + +*Note*: All nested suites will still be executed. + +Here's an example of executing a particular test case: + +```js +describe('Array', function() { + describe('#indexOf()', function() { + it.only('should return -1 unless present', function() { + // ... + }); - Pending test-cases are simply those without a callback: + it('should return the index when present', function() { + // ... + }); + }); +}); +``` - describe('Array', function(){ - describe('#indexOf()', function(){ - it('should return -1 when the value is not present') - }) - }) +*Note*: Hooks, if present, will still be executed. -

    Exclusive tests

    +*Warning*: Having more than one call to `.only()` in your tests or suites may result in unexpected behavior. - The exclusivity feature allows you to run only the specified suite or test-case - by appending `.only()` to the call as shown here: +## Inclusive Tests - describe('Array', function(){ - describe.only('#indexOf()', function(){ - ... - }) - }) +This feature is the inverse of `.only()`. By appending `.skip()`, you may tell Mocha to simply ignore these suite(s) and test case(s). Anything skipped will be marked as [pending](#pending-tests), and reported as such. Here's an example of skipping an entire suite: - Or a specific test-case: +```js +describe('Array', function() { + describe.skip('#indexOf()', function() { + // ... + }); +}); +``` - describe('Array', function(){ - describe('#indexOf()', function(){ - it.only('should return -1 unless present', function(){ +> *Best practice*: Use `.skip()` instead of commenting tests out. - }) +Or a specific test-case: - it('should return the index when present', function(){ +```js +describe('Array', function() { + describe('#indexOf()', function() { + it.skip('should return -1 unless present', function() { + // ... + }); - }) - }) - }) + it('should return the index when present', function() { + // ... + }); + }); +}); +``` - Note that currently only one `.only()` call is respected, this - effectively turns into a `--grep`. +## Dynamically Generating Tests -

    Inclusive tests

    +Given Mocha's use of `Function.prototype.call` and function expressions to define suites and test cases, it's straightforward to generate your tests dynamically. No special syntax is required — plain ol' JavaScript can be used to achieve functionality similar to "parameterized" tests, which you may have seen in other frameworks. - This feature is similar to `.only()`, however by appending `.skip()` - you may tell Mocha to simply ignore these suite(s) and test-case(s). This - puts them in a pending state, and is favoured over commenting out tests - which you may forget to uncomment. +Take the following example: - describe('Array', function(){ - describe.skip('#indexOf()', function(){ - ... - }) - }) +```js +var assert = require('assert'); - Or a specific test-case: +function add() { + return Array.prototype.slice.call(arguments).reduce(function(prev, curr) { + return prev + curr; + }, 0); +} - describe('Array', function(){ - describe('#indexOf()', function(){ - it.skip('should return -1 unless present', function(){ +describe('add()', function() { + var tests = [ + {args: [1, 2], expected: 3}, + {args: [1, 2, 3], expected: 6}, + {args: [1, 2, 3, 4], expected: 10} + ]; - }) + tests.forEach(function(test) { + it('correctly adds ' + test.args.length + ' args', function() { + var res = add.apply(null, test.args); + assert.equal(res, test.expected); + }); + }); +}); +``` - it('should return the index when present', function(){ +The above code will produce a suite with three specs: - }) - }) - }) +```sh +$ mocha -

    Meta-Generated tests

    + add() + ✓ correctly adds 2 args + ✓ correctly adds 3 args + ✓ correctly adds 4 args +``` - Given mocha's use of call statements and function expressions to define - suites and specs, it's rather straightforward to generate your tests. No - special syntax is required - plain JavaScript can be used to achieve - similar functionality as parameterized tests in other test frameworks. - Take the following example: +

    Test duration

    - var assert = require('assert'); +Many reporters will display test duration, as well as flagging tests that are slow, as shown here with the "spec" reporter: + +![test duration](images/reporter-spec-duration.png) + +To tweak what's considered "slow", you can use the `slow()` method: + +```js +describe('something slow', function() { + this.slow(10000); + + it('should take long enough for me to go make a sandwich', function() { + // ... + }); +}); +``` + + +## Timeouts + +### Suite-level - function add() { - return Array.prototype.slice.call(arguments).reduce(function(prev, curr) { - return prev + curr; - }, 0); - } +Suite-level timeouts may be applied to entire test "suites", or disabled via `this.timeout(0)`. This will be inherited by all nested suites and test-cases that do not override the value. - describe('add()', function() { - var tests = [ - {args: [1, 2], expected: 3}, - {args: [1, 2, 3], expected: 6}, - {args: [1, 2, 3, 4], expected: 10} - ]; - - tests.forEach(function(test) { - it('correctly adds ' + test.args.length + ' args', function() { - var res = add.apply(null, test.args); - assert.equal(res, test.expected); - }); - }); - }); +```js +describe('a suite of tests', function() { + this.timeout(500); - The code above will output a suite with three specs: + it('should take less than 500ms', function(done){ + setTimeout(done, 300); + }) - add() - ✓ correctly adds 2 args - ✓ correctly adds 3 args - ✓ correctly adds 4 args + it('should take less than 500ms as well', function(done){ + setTimeout(done, 200); + }) +}) +``` -

    Test duration

    +### Test-level - Most of the reporters support some form of displaying - test duration, as well as flagging tests that are slow, - as shown here with the "spec" reporter: +Test-specific timeouts may also be applied, or the use of `this.timeout(0)` to disable timeouts all together: - ![test duration](images/reporter-spec-duration.png) +```js +it('should take less than 500ms', function(done){ + this.timeout(500); + setTimeout(done, 300); +}); +``` -

    String diffs

    +## Diffs - Mocha supports the `err.expected`, and `err.actual` properties - when available to present expectations to the developer. Currently - Mocha provides string diffs, however in the future object diffs and - others may be provided. +Mocha supports the `err.expected` and `err.actual` properties of any thrown `AssertionError`s from an assertion library. Mocha will attempt to display the difference between what was expected, and what the assertion actually saw. Here's an example of a "string" diff: - ![string diffs](images/reporter-string-diffs.png) +![string diffs](images/reporter-string-diffs.png) -

    mocha(1)

    +## Usage +``` +Usage: mocha [debug] [options] [files] - Usage: mocha [debug] [options] [files] +Commands: - Commands: + init + initialize a client-side mocha setup at - init - initialize a client-side mocha setup at +Options: - Options: + -h, --help output usage information + -V, --version output the version number + -A, --async-only force all tests to take a callback (async) + -c, --colors force enabling of colors + -C, --no-colors force disabling of colors + -G, --growl enable growl notification support + -O, --reporter-options reporter-specific options + -R, --reporter specify the reporter to use + -S, --sort sort test files + -b, --bail bail after first test failure + -d, --debug enable node's debugger, synonym for node --debug + -g, --grep only run tests matching + -f, --fgrep only run tests containing + -gc, --expose-gc expose gc extension + -i, --invert inverts --grep and --fgrep matches + -r, --require require the given module + -s, --slow "slow" test threshold in milliseconds [75] + -t, --timeout set test-case timeout in milliseconds [2000] + -u, --ui specify user-interface (bdd|tdd|exports) + -w, --watch watch files for changes + --check-leaks check for global variable leaks + --compilers :,... use the given module(s) to compile files + --debug-brk enable node's debugger breaking on the first line + --globals allow the given comma-delimited global [names] + --inline-diffs display actual/expected differences inline within each string + --interfaces display available interfaces + --no-deprecation silence deprecation warnings + --no-exit require a clean shutdown of the event loop: mocha will exit + --no-timeouts disables timeouts, given implicitly with --debug + --opts specify opts path + --prof log statistical profiling information + --recursive include sub directories + --reporters display available reporters + --throw-deprecation throw an exception anytime a deprecated function is used + --trace trace function calls + --trace-deprecation show stack traces on deprecations + --watch-extensions ,... additional extensions to monitor with --watch + --delay wait for async suite definition +``` - -h, --help output usage information - -V, --version output the version number - -A, --async-only force all tests to take a callback (async) - -c, --colors force enabling of colors - -C, --no-colors force disabling of colors - -G, --growl enable growl notification support - -O, --reporter-options reporter-specific options - -R, --reporter specify the reporter to use - -S, --sort sort test files - -b, --bail bail after first test failure - -d, --debug enable node's debugger, synonym for node --debug - -g, --grep only run tests matching - -f, --fgrep only run tests containing - -gc, --expose-gc expose gc extension - -i, --invert inverts --grep and --fgrep matches - -r, --require require the given module - -s, --slow "slow" test threshold in milliseconds [75] - -t, --timeout set test-case timeout in milliseconds [2000] - -u, --ui specify user-interface (bdd|tdd|exports) - -w, --watch watch files for changes - --check-leaks check for global variable leaks - --compilers :,... use the given module(s) to compile files - --debug-brk enable node's debugger breaking on the first line - --globals allow the given comma-delimited global [names] - --inline-diffs display actual/expected differences inline within each string - --interfaces display available interfaces - --no-deprecation silence deprecation warnings - --no-exit require a clean shutdown of the event loop: mocha will exit - --no-timeouts disables timeouts, given implicitly with --debug - --opts specify opts path - --prof log statistical profiling information - --recursive include sub directories - --reporters display available reporters - --throw-deprecation throw an exception anytime a deprecated function is used - --trace trace function calls - --trace-deprecation show stack traces on deprecations - --watch-extensions ,... additional extensions to monitor with --watch - --delay wait for async suite definition +### `-w, --watch` -

    -w, --watch

    +Executes tests on changes to JavaScript in the CWD, and once initially. - Executes tests on changes to JavaScript in the CWD, and once initially. +### `--compilers` -

    --compilers

    +CoffeeScript is no longer supported out of the box. CS and similar transpilers +may be used by mapping the file extensions (for use with --watch) and the module +name. For example `--compilers coffee:coffee-script` with CoffeeScript 1.6- or +`--compilers coffee:coffee-script/register` with CoffeeScript 1.7+. - coffee-script is no longer supported out of the box. CS and similar transpilers - may be used by mapping the file extensions (for use with --watch) and the module - name. For example `--compilers coffee:coffee-script` with CoffeeScript 1.6- or - `--compilers coffee:coffee-script/register` with CoffeeScript 1.7+. +### `-b, --bail` -

    -b, --bail

    +Only interested in the first exception? use `--bail`! - Only interested in the first exception? use `--bail` ! +### `-d, --debug` -

    -d, --debug

    +Enables node's debugger support, this executes your script(s) with `node debug ` allowing you to step through code and break with the `debugger` statement. Note the difference between `mocha debug` and `mocha --debug`: `mocha debug` will fire up node's built-in debug client, `mocha --debug` will allow you to use a different interface — such as the Blink Developer Tools. - Enables node's debugger support, this executes your script(s) with `node debug ` allowing you to step through code and break with the `debugger` statement. Note the difference between `mocha debug` and `mocha --debug`: `mocha debug` will fire up node's built-in debug client, `mocha --debug` will allow you to use a different interface — such as the Blink Developer Tools. +### `--globals ` -

    --globals <names>

    +Accepts a comma-delimited list of accepted global variable names. For example, suppose your app deliberately exposes a global named `app` and `YUI`, you may want to add `--globals app,YUI`. It also accepts wildcards. You could do `--globals '*bar'` and it would match `foobar`, `barbar`, etc. You can also simply pass in `'*'` to ignore all globals. - Accepts a comma-delimited list of accepted global variable names. For example, suppose your app deliberately exposes a global named `app` and `YUI`, you may want to add `--globals app,YUI`. It also accepts wildcards. You could do `--globals '*bar'` and it would match `foobar`, `barbar`, etc. You can also simply pass in `'*'` to ignore all globals. +### `--check-leaks` -

    --check-leaks

    +By default, Mocha will not check for global variables leaked while running tests, to enable this pass `--check-leaks`, to specify globals that are acceptable use `--globals`, for example `--globals jQuery,MyLib`. - By default Mocha will not check for global variables leaked while running tests, to enable this pass `--check-leaks`, to specify globals that are acceptable use `--globals`, for example `--globals jQuery,MyLib`. +### `-r, --require ` -

    -r, --require <name>

    +The `--require` option is useful for libraries such as [should.js](https://github.com/visionmedia/should.js), so you may simply `--require should` instead of manually invoking `require('should')` within each test file. Note that this works well for `should` as it augments `Object.prototype`, however if you wish to access a module's exports you will have to require them, for example `var should = require('should')`. Furthermore, it can be used with relative paths, e.g. `--require ./test/helper.js` - The `--require` option is useful for libraries such as [should.js](https://github.com/visionmedia/should.js), so you may simply `--require should` instead of manually invoking `require('should')` within each test file. Note that this works well for `should` as it augments `Object.prototype`, however if you wish to access a module's exports you will have to require them, for example `var should = require('should')`. Furthermore, it can be used with relative paths, e.g. `--require ./test/helper.js` +### `-u, --ui ` -

    -u, --ui <name>

    +The `--ui` option lets you specify the interface to use, defaulting to "bdd". - The `--ui` option lets you specify the interface to use, defaulting to "bdd". +### `-R, --reporter ` -

    -R, --reporter <name>

    +The `--reporter` option allows you to specify the reporter that will be used, defaulting to "dot". This flag may also be used to utilize third-party reporters. For example if you `npm install mocha-lcov-reporter` you may then do `--reporter mocha-lcov-reporter`. - The `--reporter` option allows you to specify the reporter that will be used, defaulting to "dot". This flag may also be used to utilize third-party reporters. For example if you `npm install mocha-lcov-reporter` you may then do `--reporter mocha-lcov-reporter`. +### `-t, --timeout ` -

    -t, --timeout <ms>

    +Specifies the test-case timeout, defaulting to 2 seconds. To override you may pass the timeout in milliseconds, or a value with the `s` suffix, ex: `--timeout 2s` or `--timeout 2000` would be equivalent. - Specifies the test-case timeout, defaulting to 2 seconds. To override you may pass the timeout in milliseconds, or a value with the `s` suffix, ex: `--timeout 2s` or `--timeout 2000` would be equivalent. +### `-s, --slow ` -

    -s, --slow <ms>

    +Specify the "slow" test threshold, defaulting to 75ms. Mocha uses this to highlight test-cases that are taking too long. - Specify the "slow" test threshold, defaulting to 75ms. Mocha uses this to highlight test-cases that are taking too long. +### `-g, --grep ` -

    -g, --grep <pattern>

    +The `--grep` option when specified will trigger mocha to only run tests matching the given `pattern` which is internally compiled to a `RegExp`. - The `--grep` option when specified will trigger mocha to only run tests matching the given `pattern` which is internally compiled to a `RegExp`. +Suppose, for example, you have "api" related tests, as well as "app" related tests, as shown in the following snippet; One could use `--grep api` or `--grep app` to run one or the other. The same goes for any other part of a suite or test-case title, `--grep users` would be valid as well, or even `--grep GET`. - Suppose for example you have "api" related tests, as well as "app" related tests, as shown in the following snippet; One could use `--grep api` or `--grep app` to run one or the other. The same goes for any other part of a suite or test-case title, `--grep users` would be valid as well, or even `--grep GET`. +```js +describe('api', function() { + describe('GET /api/users', function() { + it('respond with an array of users', function() { + // ... + }); + }); +}); - describe('api', function(){ - describe('GET /api/users', function(){ - it('respond with an array of users') - }) - }) +describe('app', function() { + describe('GET /users', function() { + it('respond with an array of users', function() { + // ... + }); + }) +}) +``` - describe('app', function(){ - describe('GET /users', function(){ - it('respond with an array of users') - }) - }) +## Interfaces -

    Interfaces

    +Mocha's "interface" system allows developers to choose their style of DSL. Mocha has **BDD**, **TDD**, **Exports**, **QUnit** and **Require**-style interfaces. - Mocha "interface" system allows developers to choose their style of DSL. Shipping with __BDD__, __TDD__, and __exports__ flavoured interfaces. +### BDD -

    BDD

    +The **BDD** interface provides `describe()`, `context()`, `it()`, `before()`, `after()`, `beforeEach()`, and `afterEach()`. - The "__BDD__" interface provides `describe()`, `context()`, `it()`, `before()`, `after()`, `beforeEach()`, and `afterEach()`: +`context()` is just an alias for `describe()`, and behaves the same way; it just provides a way to keep tests easier to read and organized. - `context()` is just an alias for `describe()`, and behaves the same way; it just provides a way to keep tests easier to read and organized. +> All of the previous examples were written using the **BDD** interface. - describe('Array', function(){ - before(function(){ - // ... - }); +```js + describe('Array', function() { + before(function() { + // ... + }); - describe('#indexOf()', function(){ - context('when not present', function(){ - it('should not throw an error', function(){ - (function(){ - [1,2,3].indexOf(4); - }).should.not.throw(); - }); - it('should return -1', function(){ - [1,2,3].indexOf(4).should.equal(-1); - }); + describe('#indexOf()', function() { + context('when not present', function() { + it('should not throw an error', function() { + (function() { + [1,2,3].indexOf(4); + }).should.not.throw(); + }); + it('should return -1', function() { + [1,2,3].indexOf(4).should.equal(-1); }); - context('when present', function(){ - it('should return the index where the element first appears in the array', function(){ - [1,2,3].indexOf(3).should.equal(2); - }); + }); + context('when present', function() { + it('should return the index where the element first appears in the array', function() { + [1,2,3].indexOf(3).should.equal(2); }); }); }); + }); +``` -

    TDD

    +### TDD - The "__TDD__" interface provides `suite()`, `test()`, `suiteSetup()`, `suiteTeardown()`, `setup()`, and `teardown()`. +The **TDD** interface provides `suite()`, `test()`, `suiteSetup()`, `suiteTeardown()`, `setup()`, and `teardown()`: - suite('Array', function(){ - setup(function(){ - // ... - }); +```js +suite('Array', function() { + setup(function() { + // ... + }); - suite('#indexOf()', function(){ - test('should return -1 when not present', function(){ - assert.equal(-1, [1,2,3].indexOf(4)); - }); - }); + suite('#indexOf()', function() { + test('should return -1 when not present', function() { + assert.equal(-1, [1,2,3].indexOf(4)); }); + }); +}); +``` -

    Exports

    +### Exports - The "__exports__" interface is much like Mocha's predecessor [expresso](https://github.com/visionmedia/expresso). The keys `before`, `after`, `beforeEach`, and `afterEach` are special-cased, object values - are suites, and function values are test-cases. +The **Exports** interface is much like Mocha's predecessor [expresso](https://github.com/visionmedia/expresso). The keys `before`, `after`, `beforeEach`, and `afterEach` are special-cased, object values are suites, and function values are test-cases: - module.exports = { - before: function(){ - // ... - }, +```js +module.exports = { + before: function() { + // ... + }, - 'Array': { - '#indexOf()': { - 'should return -1 when not present': function(){ - [1,2,3].indexOf(4).should.equal(-1); - } - } + 'Array': { + '#indexOf()': { + 'should return -1 when not present': function() { + [1,2,3].indexOf(4).should.equal(-1); } - }; + } + } +}; +``` -

    QUnit

    +### QUnit - The qunit-inspired interface matches the "flat" look of QUnit where the test suite title is simply defined before the test-cases. Like TDD, it uses `suite()` and `test()`, but resembling BDD it also contains `before()`, `after()`, `beforeEach()`, and `afterEach()`. +The [QUnit](http://qunitjs.com)-inspired interface matches the "flat" look of QUnit, where the test suite title is simply defined before the test-cases. Like TDD, it uses `suite()` and `test()`, but resembling BDD, it also contains `before()`, `after()`, `beforeEach()`, and `afterEach()`. - function ok(expr, msg) { - if (!expr) throw new Error(msg); - } +```js +function ok(expr, msg) { + if (!expr) throw new Error(msg); +} - suite('Array'); +suite('Array'); - test('#length', function(){ - var arr = [1,2,3]; - ok(arr.length == 3); - }); +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); - }); +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'); +suite('String'); - test('#length', function(){ - ok('foo'.length == 3); - }); +test('#length', function() { + ok('foo'.length == 3); +}); +``` -

    Require

    +### Require - The `require` interface allows you to require the `describe` and friend words - directly using `require` and call them whatever you want. This interface - is also useful if you want to avoid global variables in your tests. +The `require` interface allows you to require the `describe` and friend words directly using `require` and call them whatever you want. This interface is also useful if you want to avoid global variables in your tests. - Note this works when you run your tests via the `mocha` executable only, and not when using the `node` executable directly. The reason is that - certain methods are exposed at runtime and when using the `mocha` executable only. +*Note*: The `require` interface cannot be run via the `node` executable, and must be run via `mocha`. - var testCase = require('mocha').describe - var pre = require('mocha').before - var assertions = require('mocha').it - var assert = require('assert') +```js +var testCase = require('mocha').describe +var pre = require('mocha').before +var assertions = require('mocha').it +var assert = require('assert') - testCase('Array', function(){ - pre(function(){ - // ... - }); +testCase('Array', function() { + pre(function() { + // ... + }); - testCase('#indexOf()', function(){ - assertions('should return -1 when not present', function(){ - assert.equal([1,2,3].indexOf(4), -1); - }); - }); + testCase('#indexOf()', function() { + assertions('should return -1 when not present', function() { + assert.equal([1,2,3].indexOf(4), -1); }); + }); +}); +``` -

    Reporters

    +## Reporters - Mocha reporters adjust to the terminal window, - and always disable ansi-escape colouring when - the stdio streams are not associated with a tty. +Mocha reporters adjust to the terminal window, and always disable ANSI-escape coloring when the stdio streams are not associated with a TTY. -

    Dot Matrix

    +### Spec - The "dot" matrix reporter is simply a series of dots - that represent test cases, failures highlight in red, - pending in blue, slow as yellow. +This is the default reporter. The "spec" reporter outputs a hierarchical view nested just as the test cases are. - ![dot matrix reporter](images/reporter-dot.png) +![spec reporter](images/reporter-spec.png) +![spec reporter with failure](images/reporter-spec-fail.png) -

    Spec

    +### Dot Matrix - The "spec" reporter outputs a hierarchical view - nested just as the test cases are. +The dot matrix (or "dot") reporter is simply a series of dots that represent test cases, failures highlight in red, pending in blue, slow as yellow. Good if you would like minimal output. - ![spec reporter](images/reporter-spec.png) - ![spec reporter with failure](images/reporter-spec-fail.png) +![dot matrix reporter](images/reporter-dot.png) -

    Nyan

    +### Nyan - The "nyan" reporter is exactly what you might expect: +The "nyan" reporter is exactly what you might expect: - ![js nyan cat reporter](images/reporter-nyan.png) +![js nyan cat reporter](images/reporter-nyan.png) -

    TAP

    +### TAP - The TAP reporter emits lines for a [Test-Anything-Protocol](http://en.wikipedia.org/wiki/Test_Anything_Protocol) consumer. +The TAP reporter emits lines for a [Test-Anything-Protocol](http://en.wikipedia.org/wiki/Test_Anything_Protocol) consumer. - ![test anything protocol](images/reporter-tap.png) +![test anything protocol](images/reporter-tap.png) -

    Landing Strip

    +### Landing Strip - The Landing Strip reporter is a gimmicky test reporter simulating - a plane landing :) unicode ftw +The 'Landing Strip' reporter is a gimmicky test reporter simulating a plane landing :) unicode ftw - ![landing strip plane reporter](images/reporter-landing.png) - ![landing strip with failure](images/reporter-landing-fail.png) +![landing strip plane reporter](images/reporter-landing.png) +![landing strip with failure](images/reporter-landing-fail.png) -

    List

    +### List - The "List" reporter outputs a simple specifications list as - test cases pass or fail, outputting the failure details at - the bottom of the output. +The "list" reporter outputs a simple specifications list as test cases pass or fail, outputting the failure details at the bottom of the output. - ![list reporter](images/reporter-list.png) +![list reporter](images/reporter-list.png) -

    Progress

    +### Progress - The progress reporter implements a simple progress-bar: +The "progress" reporter implements a simple progress-bar: - ![progress bar](images/reporter-progress.png) +![progress bar](images/reporter-progress.png) -

    JSON

    +### JSON - The JSON reporter outputs a single large JSON object when - the tests have completed (failures or not). +The "JSON" reporter outputs a single large JSON object when the tests have completed (failures or not). - ![json reporter](images/reporter-json.png) +![json reporter](images/reporter-json.png) -

    JSON Stream

    +### JSON Stream - The JSON Stream reporter outputs newline-delimited JSON "events" as they occur, beginning with a "start" event, followed by test passes or failures, and then the final "end" event. +The "JSON stream" reporter outputs newline-delimited JSON "events" as they occur, beginning with a "start" event, followed by test passes or failures, and then the final "end" event. - ![json stream reporter](images/reporter-json-stream.png) +![json stream reporter](images/reporter-json-stream.png) -

    JSONCov

    +### JSONCov - The JSONCov reporter is similar to the JSON reporter, however when run against a library instrumented by [node-jscoverage](https://github.com/visionmedia/node-jscoverage) it will produce coverage output. +The "JSONCov" reporter is similar to the JSON reporter, however when run against a library instrumented by [node-jscoverage](https://github.com/visionmedia/node-jscoverage) it will produce coverage output. -

    HTMLCov

    +### HTMLCov - The HTMLCov reporter extends the JSONCov reporter. The library being tested should first be instrumented by [node-jscoverage](https://github.com/visionmedia/node-jscoverage), this allows Mocha to capture the coverage information necessary to produce a single-page HTML report. +The "HTMLCov" reporter extends the JSONCov reporter. The library being tested should first be instrumented by [node-jscoverage](https://github.com/visionmedia/node-jscoverage), this allows Mocha to capture the coverage information necessary to produce a single-page HTML report. - Click to view the current [Express test coverage](coverage.html) report. For an integration example view the mocha test coverage support [commit](https://github.com/visionmedia/express/commit/b6ee5fafd0d6c79cf7df5560cb324ebee4fe3a7f) for Express. +For an integration example, view the mocha test coverage support [commit](https://github.com/visionmedia/express/commit/b6ee5fafd0d6c79cf7df5560cb324ebee4fe3a7f) for Express. - ![code coverage reporting](images/reporter-htmlcov.png) +![code coverage reporting](images/reporter-htmlcov.png) -

    Min

    +### Min - The "min" reporter displays the summary only, while still outputting errors - on failure. This reporter works great with `--watch` as it clears the terminal - in order to keep your test summary at the top. +The "min" reporter displays the summary only, while still outputting errors on failure. This reporter works great with `--watch` as it clears the terminal in order to keep your test summary at the top. - ![min reporter](images/reporter-min.png) +![min reporter](images/reporter-min.png) -

    Doc

    +### Doc - The "doc" reporter outputs a hierarchical HTML body representation - of your tests, wrap it with a header, footer, some styling and you - have some fantastic documentation! +The "doc" reporter outputs a hierarchical HTML body representation of your tests. Wrap it with a header, footer, and some styling, then you have some fantastic documentation! - ![doc reporter](images/reporter-doc.png) +![doc reporter](images/reporter-doc.png) - For example suppose you have the following JavaScript: +For example, suppose you have the following JavaScript: - describe('Array', function(){ - describe('#indexOf()', function(){ - it('should return -1 when the value is not present', function(){ - [1,2,3].indexOf(5).should.equal(-1); - [1,2,3].indexOf(0).should.equal(-1); - }) - }) - }) +``` +describe('Array', function() { + describe('#indexOf()', function() { + it('should return -1 when the value is not present', function() { + [1,2,3].indexOf(5).should.equal(-1); + [1,2,3].indexOf(0).should.equal(-1); + }); + }); +}); +``` - The command `mocha --reporter doc array` would yield: +The command `mocha --reporter doc array` would yield: +```html +
    +

    Array

    +
    -

    Array

    +

    #indexOf()

    -
    -

    #indexOf()

    -
    -
    should return -1 when the value is not present
    -
    [1,2,3].indexOf(5).should.equal(-1);
    -    [1,2,3].indexOf(0).should.equal(-1);
    -
    -
    +
    should return -1 when the value is not present
    +
    [1,2,3].indexOf(5).should.equal(-1);
    +[1,2,3].indexOf(0).should.equal(-1);
    +
    +
    +``` - The SuperAgent request library [test documentation](http://visionmedia.github.io/superagent/docs/test.html) was generated with Mocha's doc reporter using this simple make target: - - test-docs: - make test REPORTER=doc \ - | cat docs/head.html - docs/tail.html \ - > docs/test.html - - View the entire [Makefile](https://github.com/visionmedia/superagent/blob/master/Makefile) for reference. - -

    XUnit

    - - Documentation needed. - -

    TeamCity

    - - Documentation needed. - -

    Markdown

    +The SuperAgent request library [test documentation](http://visionmedia.github.io/superagent/docs/test.html) was generated with Mocha's doc reporter using this simple make target: - The "markdown" reporter generates a markdown TOC and body for your - test suite. This is great if you want to use the tests as documentation - within a Github wiki page, or a markdown file in the repository that - Github can render. For example here is the Connect [test output](https://github.com/senchalabs/connect/blob/90a725343c2945aaee637e799b1cd11e065b2bff/tests.md). +```makefile + test-docs: + make test REPORTER=doc \ + | cat docs/head.html - docs/tail.html \ + > docs/test.html +``` -

    HTML

    +View the entire [Makefile](https://github.com/visionmedia/superagent/blob/master/Makefile) for reference. - The __HTML__ reporter is currently the only browser reporter - supported by Mocha, and it looks like this: +### Markdown - ![HTML test reporter](images/reporter-html.png) +The "markdown" reporter generates a markdown TOC and body for your test suite. This is great if you want to use the tests as documentation within a Github wiki page, or a markdown file in the repository that Github can render. For example here is the Connect [test output](https://github.com/senchalabs/connect/blob/90a725343c2945aaee637e799b1cd11e065b2bff/tests.md). -

    Browser support

    +### HTML - Mocha runs in the browser. Every release of Mocha will have new builds of _./mocha.js_ and _./mocha.css_ for use in the browser. To setup Mocha for browser use all you have to do is include the script, stylesheet, tell Mocha which interface you wish to use, and then run the tests. A typical setup might look something like the following, where we call `mocha.setup('bdd')` to use the __BDD__ interface before loading the test scripts, running them `onload` with `mocha.run()`. +The "HTML" reporter is currently the only browser reporter supported by Mocha, and it looks like this: - - - - Mocha Tests - - - -
    - - - - - - - - - - +![HTML test reporter](images/reporter-html.png) -

    grep

    - - The client-side may use `--grep` as well, however, you must append a query-string to your URL: `?grep=api`. - -

    Mocha Setup in the Browser

    - - Mocha options can be set via `mocha.setup()`. Examples: - - // Use "tdd" interface. This is a shortcut to setting the interface; - // any other options must be passed via an object. - mocha.setup('tdd'); - - // This is equivalent to the above. - mocha.setup({ - ui: 'tdd' - }); - - // Use "tdd" interface, ignore leaks, and force all tests to be asynchronous - mocha.setup({ - ui: 'tdd', - ignoreLeaks: true, - asyncOnly: true - }); +### Undocumented Reporters -

    Browser-specific option(s)

    +The "XUnit" and "TeamCity" reporters are also available, but someone needs to write the documentation. - The following option(s) *only* function in a browser context: +## Running Mocha in the Browser - `noHighlighting` : If set to `true`, do not attempt to use syntax highlighting on output test code. +Mocha runs in the browser. Every release of Mocha will have new builds of `./mocha.js` and `./mocha.css` for use in the browser. -

    mocha.opts

    +To configure Mocha for use in the browser, you must include the relevant files, tell Mocha which interface you would like to use, and then tell it to begin the tests. - Mocha will attempt to load `./test/mocha.opts`, these are concatenated with `process.argv`, though command-line args will take precedence. For example suppose you have the following _mocha.opts_ file: +A typical setup might look something like the following, where we call `mocha.setup('bdd')` to use the **BDD** interface before loading the test scripts, running them `onload` with `mocha.run()`. - --require should - --reporter dot - --ui bdd +```html + + + + Mocha Tests + + + +
    + + + + + + + + + + +``` - This will default the reporter to `dot`, require the `should` library, - and use `bdd` as the interface. With this you may then invoke `mocha(1)` - with additional arguments, here enabling growl support and changing - the reporter to `list`: +### Grep - $ mocha --reporter list --growl +The browser may use the `--grep` as functionality. Append a query-string to your URL: `?grep=api`. -

    Suite specific timeouts

    +### Browser Configuration - Suite-level timeouts may be applied to entire test "suites", or disabled - via `this.timeout(0)`. This will be inherited by all nested suites and test-cases - that do not override the value. +Mocha options can be set via `mocha.setup()`. Examples: - describe('a suite of tests', function(){ - this.timeout(500); +```js +// Use "tdd" interface. This is a shortcut to setting the interface; +// any other options must be passed via an object. +mocha.setup('tdd'); - it('should take less than 500ms', function(done){ - setTimeout(done, 300); - }) +// This is equivalent to the above. +mocha.setup({ + ui: 'tdd' +}); - it('should take less than 500ms as well', function(done){ - setTimeout(done, 200); - }) - }) +// Use "tdd" interface, ignore leaks, and force all tests to be asynchronous +mocha.setup({ + ui: 'tdd', + ignoreLeaks: true, + asyncOnly: true +}); +``` +### Browser-specific Option(s) -

    Test specific timeouts

    +The following option(s) *only* function in a browser context: - Test-specific timeouts may also be applied, or the use of `this.timeout(0)` - to disable timeouts all together: +`noHighlighting`: If set to `true`, do not attempt to use syntax highlighting on output test code. - it('should take less than 500ms', function(done){ - this.timeout(500); - setTimeout(done, 300); - }) +## `mocha.opts` -

    Best practices

    +Back on the server, Mocha will attempt to load `./test/mocha.opts` as a configuration file of sorts. The lines in this file are combined with any command-line arguments. The command-line arguments take precedence. For example, suppose you have the following `mocha.opts` file: -

    test/*

    +``` + --require should + --reporter dot + --ui bdd +``` - By default `mocha(1)` will use the pattern `./test/*.js`, so - it's usually a good place to put your tests. +This will default the reporter to `dot`, require the `should` library, and use `bdd` as the interface. With this, you may then invoke `mocha` with additional arguments, here enabling [Growl](http://growl.info) support, and changing the reporter to `list`: -

    Makefiles

    +```sh +$ mocha --reporter list --growl +``` - Be kind and don't make developers hunt around in your docs to figure - out how to run the tests, add a `make test` target to your _Makefile_: +## The `test/` Directory - test: - ./node_modules/.bin/mocha --reporter list +By default, `mocha` looks for the glob `./test/*.js`, so you may want to put your tests in `test/` folder. - .PHONY: test +## Editor Plugins -

    Editors

    +The following editor-related packages are available: - The following editor-related packages are available: +### TextMate -

    TextMate bundle

    +The Mocha TextMate bundle includes snippets to make writing tests quicker and more enjoyable. To install the bundle, clone a copy of the [Mocha repo](https://github.com/mochajs/mocha), and run: - The Mocha TextMate bundle includes snippets to - make writing tests quicker and more enjoyable. - To install the bundle run: +```sh +$ make tm +``` - $ make tm +### JetBrains -

    JetBrains plugin

    +[JetBrains](http://jetbrains.com) provides a [NodeJS plugin](http://www.jetbrains.com/idea/features/nodejs.html) for its suite of IDEs (IntelliJ IDEA, WebStorm, etc.), which contains a Mocha test runner, among other things. - [JetBrains](http://jetbrains.com) provides a [NodeJS plugin](http://www.jetbrains.com/idea/features/nodejs.html) for its suite of IDEs (IntelliJ IDEA, WebStorm, etc.), which contains a Mocha test runner, among other things. +![JetBrains Mocha Runner Plugin in Action](images/jetbrains-plugin.png) - ![JetBrains Mocha Runner Plugin in Action](images/jetbrains-plugin.png) +The plugin is titled **NodeJS**, and can be installed via **Preferences** > **Plugins**, assuming your license allows it. - The plugin is titled **NodeJS**, and can be installed via **Preferences** > **Plugins**, or via [direct download](http://plugins.jetbrains.com/plugin/6098?pr=phpStorm). -

    Example test suites

    +## Examples - The following test suites are from real projects putting Mocha to use, - so they serve as good examples: +Real live example code: - - [Express](https://github.com/visionmedia/express/tree/master/test) - - [Connect](https://github.com/senchalabs/connect/tree/master/test) - - [SuperAgent](https://github.com/visionmedia/superagent/tree/master/test/node) - - [WebSocket.io](https://github.com/LearnBoost/websocket.io/tree/master/test) - - [Mocha](https://github.com/mochajs/mocha/tree/master/test) +- [Express](https://github.com/visionmedia/express/tree/master/test) +- [Connect](https://github.com/senchalabs/connect/tree/master/test) +- [SuperAgent](https://github.com/visionmedia/superagent/tree/master/test/node) +- [WebSocket.io](https://github.com/LearnBoost/websocket.io/tree/master/test) +- [Mocha](https://github.com/mochajs/mocha/tree/master/test) -

    Running mocha's tests

    +## Testing Mocha - Run the tests: +To run Mocha's tests: - $ make test +```sh +$ make test +``` - Run all tests, including interfaces: +Run all tests, including interfaces: - $ make test-all +```sh +$ make test-all +``` - Alter the reporter: +Alter the reporter: - $ make test REPORTER=list +``` +$ make test REPORTER=list +``` -

    More information

    +## More Information - For additional information such as using spies, mocking, and shared behaviours be sure to check out the [Mocha Wiki](https://github.com/mochajs/mocha/wiki) on GitHub. For discussions join the [Google Group](http://groups.google.com/group/mochajs). For a running example of mocha view [example/tests.html](example/tests.html). For the JavaScript API view the [source](https://github.com/mochajs/mocha/blob/master/lib/mocha.js#L51). +In addition to chatting with us on [Gitter](https://gitter.im/mochajs/mocha), for additional information such as using spies, mocking, and shared behaviours be sure to check out the [Mocha Wiki](https://github.com/mochajs/mocha/wiki) on GitHub. For discussions join the [Google Group](http://groups.google.com/group/mochajs). For a running example of Mocha, view [example/tests.html](example/tests.html). For the JavaScript API, view the [source](https://github.com/mochajs/mocha/blob/master/lib/mocha.js#L51). diff --git a/jquery.js b/jquery.js deleted file mode 100644 index d2424e6528..0000000000 --- a/jquery.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! jQuery v1.7 jquery.com | jquery.org/license */ -(function(a,b){function cA(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cx(a){if(!cm[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cn||(cn=c.createElement("iframe"),cn.frameBorder=cn.width=cn.height=0),b.appendChild(cn);if(!co||!cn.createElement)co=(cn.contentWindow||cn.contentDocument).document,co.write((c.compatMode==="CSS1Compat"?"":"")+""),co.close();d=co.createElement(a),co.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cn)}cm[a]=e}return cm[a]}function cw(a,b){var c={};f.each(cs.concat.apply([],cs.slice(0,b)),function(){c[this]=a});return c}function cv(){ct=b}function cu(){setTimeout(cv,0);return ct=f.now()}function cl(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ck(){try{return new a.XMLHttpRequest}catch(b){}}function ce(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g0){c!=="border"&&f.each(e,function(){c||(d-=parseFloat(f.css(a,"padding"+this))||0),c==="margin"?d+=parseFloat(f.css(a,c+this))||0:d-=parseFloat(f.css(a,"border"+this+"Width"))||0});return d+"px"}d=bB(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0,c&&f.each(e,function(){d+=parseFloat(f.css(a,"padding"+this))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+this+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+this))||0)});return d+"px"}function br(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bi,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bq(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bp(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bp)}function bp(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bo(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bn(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bm(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d=0===c})}function V(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function N(){return!0}function M(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/\d/,n=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,o=/^[\],:{}\s]*$/,p=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,q=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,r=/(?:^|:|,)(?:\s*\[)+/g,s=/(webkit)[ \/]([\w.]+)/,t=/(opera)(?:.*version)?[ \/]([\w.]+)/,u=/(msie) ([\w.]+)/,v=/(mozilla)(?:.*? rv:([\w.]+))?/,w=/-([a-z]|[0-9])/ig,x=/^-ms-/,y=function(a,b){return(b+"").toUpperCase()},z=d.userAgent,A,B,C,D=Object.prototype.toString,E=Object.prototype.hasOwnProperty,F=Array.prototype.push,G=Array.prototype.slice,H=String.prototype.trim,I=Array.prototype.indexOf,J={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=n.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7",length:0,size:function(){return this.length},toArray:function(){return G.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?F.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),B.add(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(G.apply(this,arguments),"slice",G.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:F,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j0)return;B.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").unbind("ready")}},bindReady:function(){if(!B){B=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",C,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",C),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&K()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return a!=null&&m.test(a)&&!isNaN(a)},type:function(a){return a==null?String(a):J[D.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!E.call(a,"constructor")&&!E.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||E.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw a},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(o.test(b.replace(p,"@").replace(q,"]").replace(r,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(x,"ms-").replace(w,y)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c
    a",d=a.getElementsByTagName("*"),e=a.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=a.getElementsByTagName("input")[0],k={leadingWhitespace:a.firstChild.nodeType===3,tbody:!a.getElementsByTagName("tbody").length,htmlSerialize:!!a.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,unknownElems:!!a.getElementsByTagName("nav").length,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:a.className!=="t",enctype:!!c.createElement("form").enctype,submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,k.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,k.optDisabled=!h.disabled;try{delete a.test}catch(v){k.deleteExpando=!1}!a.addEventListener&&a.attachEvent&&a.fireEvent&&(a.attachEvent("onclick",function(){k.noCloneEvent=!1}),a.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),k.radioValue=i.value==="t",i.setAttribute("checked","checked"),a.appendChild(i),l=c.createDocumentFragment(),l.appendChild(a.lastChild),k.checkClone=l.cloneNode(!0).cloneNode(!0).lastChild.checked,a.innerHTML="",a.style.width=a.style.paddingLeft="1px",m=c.getElementsByTagName("body")[0],o=c.createElement(m?"div":"body"),p={visibility:"hidden",width:0,height:0,border:0,margin:0,background:"none"},m&&f.extend(p,{position:"absolute",left:"-999px",top:"-999px"});for(t in p)o.style[t]=p[t];o.appendChild(a),n=m||b,n.insertBefore(o,n.firstChild),k.appendChecked=i.checked,k.boxModel=a.offsetWidth===2,"zoom"in a.style&&(a.style.display="inline",a.style.zoom=1,k.inlineBlockNeedsLayout=a.offsetWidth===2,a.style.display="",a.innerHTML="
    ",k.shrinkWrapBlocks=a.offsetWidth!==2),a.innerHTML="
    t
    ",q=a.getElementsByTagName("td"),u=q[0].offsetHeight===0,q[0].style.display="",q[1].style.display="none",k.reliableHiddenOffsets=u&&q[0].offsetHeight===0,a.innerHTML="",c.defaultView&&c.defaultView.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",a.appendChild(j),k.reliableMarginRight=(parseInt((c.defaultView.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(a.attachEvent)for(t in{submit:1,change:1,focusin:1})s="on"+t,u=s in a,u||(a.setAttribute(s,"return;"),u=typeof a[s]=="function"),k[t+"Bubbles"]=u;f(function(){var a,b,d,e,g,h,i=1,j="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",l="visibility:hidden;border:0;",n="style='"+j+"border:5px solid #000;padding:0;'",p="
    "+""+"
    ";m=c.getElementsByTagName("body")[0];!m||(a=c.createElement("div"),a.style.cssText=l+"width:0;height:0;position:static;top:0;margin-top:"+i+"px",m.insertBefore(a,m.firstChild),o=c.createElement("div"),o.style.cssText=j+l,o.innerHTML=p,a.appendChild(o),b=o.firstChild,d=b.firstChild,g=b.nextSibling.firstChild.firstChild,h={doesNotAddBorder:d.offsetTop!==5,doesAddBorderForTableAndCells:g.offsetTop===5},d.style.position="fixed",d.style.top="20px",h.fixedPosition=d.offsetTop===20||d.offsetTop===15,d.style.position=d.style.top="",b.style.overflow="hidden",b.style.position="relative",h.subtractsBorderForOverflowNotVisible=d.offsetTop===-5,h.doesNotIncludeMarginInBodyOffset=m.offsetTop!==i,m.removeChild(a),o=a=null,f.extend(k,h))}),o.innerHTML="",n.removeChild(o),o=l=g=h=m=j=a=i=null;return k}(),f.boxModel=f.support.boxModel;var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[f.expando]:a[f.expando]&&f.expando,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[f.expando]=n=++f.uuid:n=f.expando),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[f.expando]:f.expando;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)?b=b:b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" "));for(e=0,g=b.length;e-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];if(!arguments.length){if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}return b}e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!a||j===3||j===8||j===2)return b;if(e&&c in f.attrFn)return f(a)[c](d);if(!("getAttribute"in a))return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return b}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g},removeAttr:function(a,b){var c,d,e,g,h=0;if(a.nodeType===1){d=(b||"").split(p),g=d.length;for(;h=0}})});var z=/\.(.*)$/,A=/^(?:textarea|input|select)$/i,B=/\./g,C=/ /g,D=/[^\w\s.|`]/g,E=/^([^\.]*)?(?:\.(.+))?$/,F=/\bhover(\.\S+)?/,G=/^key/,H=/^(?:mouse|contextmenu)|click/,I=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,J=function(a){var b=I.exec(a);b&& -(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},K=function(a,b){return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||a.id===b[2])&&(!b[3]||b[3].test(a.className))},L=function(a){return f.event.special.hover?a:a.replace(F,"mouseenter$1 mouseleave$1")};f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=L(c).split(" ");for(k=0;k=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"",(g||!e)&&c.preventDefault();if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,n=null;for(m=e.parentNode;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l=0:t===b&&(t=o[s]=r.quick?K(m,r.quick):f(m).is(s)),t&&q.push(r);q.length&&j.push({elem:m,matches:q})}d.length>e&&j.push({elem:this,matches:d.slice(e)});for(k=0;k0?this.bind(b,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),G.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),H.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return bc[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="

    ";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="
    ";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h0)for(h=g;h=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(V(c[0])||V(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c),g=S.call(arguments);O.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!U[a]?f.unique(e):e,(this.length>1||Q.test(d))&&P.test(a)&&(e=e.reverse());return this.pushStack(e,a,g.join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var Y="abbr article aside audio canvas datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video",Z=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,_=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,ba=/<([\w:]+)/,bb=/",""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]},bk=X(c);bj.optgroup=bj.option,bj.tbody=bj.tfoot=bj.colgroup=bj.caption=bj.thead,bj.th=bj.td,f.support.htmlSerialize||(bj._default=[1,"div
    ","
    "]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){f(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after" -,arguments);a.push.apply(a,f(arguments[0]).toArray());return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Z,""):null;if(typeof a=="string"&&!bd.test(a)&&(f.support.leadingWhitespace||!$.test(a))&&!bj[(ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(_,"<$1>");try{for(var c=0,d=this.length;c1&&l0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d=a.cloneNode(!0),e,g,h;if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bn(a,d),e=bo(a),g=bo(d);for(h=0;e[h];++h)g[h]&&bn(e[h],g[h])}if(b){bm(a,d);if(c){e=bo(a),g=bo(d);for(h=0;e[h];++h)bm(e[h],g[h])}}e=g=null;return d},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!bc.test(k))k=b.createTextNode(k);else{k=k.replace(_,"<$1>");var l=(ba.exec(k)||["",""])[1].toLowerCase(),m=bj[l]||bj._default,n=m[0],o=b.createElement("div");b===c?bk.appendChild(o):X(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=bb.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]===""&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&$.test(k)&&o.insertBefore(b.createTextNode($.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return bt.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bs,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bs.test(g)?g.replace(bs,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bB(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bC=function(a,c){var d,e,g;c=c.replace(bu,"-$1").toLowerCase();if(!(e=a.ownerDocument.defaultView))return b;if(g=e.getComputedStyle(a,null))d=g.getPropertyValue(c),d===""&&!f.contains(a.ownerDocument.documentElement,a)&&(d=f.style(a,c));return d}),c.documentElement.currentStyle&&(bD=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bv.test(f)&&bw.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bB=bC||bD,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bF=/%20/g,bG=/\[\]$/,bH=/\r?\n/g,bI=/#.*$/,bJ=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bK=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bL=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bM=/^(?:GET|HEAD)$/,bN=/^\/\//,bO=/\?/,bP=/)<[^<]*)*<\/script>/gi,bQ=/^(?:select|textarea)/i,bR=/\s+/,bS=/([?&])_=[^&]*/,bT=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bU=f.fn.load,bV={},bW={},bX,bY,bZ=["*/"]+["*"];try{bX=e.href}catch(b$){bX=c.createElement("a"),bX.href="",bX=bX.href}bY=bT.exec(bX.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bU)return bU.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("
    ").append(c.replace(bP,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bQ.test(this.nodeName)||bK.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bH,"\r\n")}}):{name:b.name,value:c.replace(bH,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.bind(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?cb(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),cb(a,b);return a},ajaxSettings:{url:bX,isLocal:bL.test(bY[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bZ},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:b_(bV),ajaxTransport:b_(bW),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cd(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=ce(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bJ.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bI,"").replace(bN,bY[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bR),d.crossDomain==null&&(r=bT.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bY[1]&&r[2]==bY[2]&&(r[3]||(r[1]==="http:"?80:443))==(bY[3]||(bY[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),ca(bV,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bM.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bO.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bS,"$1_="+x);d.url=y+(y===d.url?(bO.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bZ+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=ca(bW,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){s<2?w(-1,z):f.error(z)}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)cc(g,a[g],c,e);return d.join("&").replace(bF,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cf=f.now(),cg=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cf++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(cg.test(b.url)||e&&cg.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(cg,l),b.url===j&&(e&&(k=k.replace(cg,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var ch=a.ActiveXObject?function(){for(var a in cj)cj[a](0,1)}:!1,ci=0,cj;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ck()||cl()}:ck,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,ch&&delete cj[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++ci,ch&&(cj||(cj={},f(a).unload(ch)),cj[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var cm={},cn,co,cp=/^(?:toggle|show|hide)$/,cq=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cr,cs=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],ct;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cw("show",3),a,b,c);for(var g=0,h=this.length;g=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cz.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cz.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cA(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cA(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f})(window); \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000000..db0dd34f95 --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "mochajs.org", + "version": "1.0.0", + "description": "Mocha's gh-pages branch", + "private": true, + "scripts": { + "install": "bundle install", + "build": "toc index.md && bundle exec jekyll build" + }, + "repository": { + "type": "git", + "url": "https://github.com/mochajs/mocha.git#gh-pages" + }, + "license": "MIT", + "bugs": { + "url": "https://github.com/mochajs/mocha/issues" + }, + "homepage": "http://mochajs.org", + "devDependencies": { + "marked-toc": "^0.3.0" + } +}