diff options
author | Aldo Cortesi <aldo@nullcube.com> | 2014-09-10 14:22:26 +1200 |
---|---|---|
committer | Aldo Cortesi <aldo@nullcube.com> | 2014-09-10 14:23:10 +1200 |
commit | 0510c9b111aed03d0d3680db63614d50f231745c (patch) | |
tree | 0d2fec5d46a3cb984a8b12e36db2f44a1a8eaa5a /web/src/vendor/benchmark | |
parent | 76982937a68a2adaf96ec2d258e369d7c871a609 (diff) | |
download | mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.tar.gz mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.tar.bz2 mitmproxy-0510c9b111aed03d0d3680db63614d50f231745c.zip |
Client-side framework for web application
Diffstat (limited to 'web/src/vendor/benchmark')
45 files changed, 20358 insertions, 0 deletions
diff --git a/web/src/vendor/benchmark/.bower.json b/web/src/vendor/benchmark/.bower.json new file mode 100644 index 00000000..83417220 --- /dev/null +++ b/web/src/vendor/benchmark/.bower.json @@ -0,0 +1,14 @@ +{ + "name": "benchmark", + "homepage": "https://github.com/bestiejs/benchmark.js", + "version": "1.0.0", + "_release": "1.0.0", + "_resolution": { + "type": "version", + "tag": "v1.0.0", + "commit": "f3c1476cfac950b186b167843077f2cf7014f080" + }, + "_source": "git://github.com/bestiejs/benchmark.js.git", + "_target": "*", + "_originalSource": "benchmark" +}
\ No newline at end of file diff --git a/web/src/vendor/benchmark/.gitattributes b/web/src/vendor/benchmark/.gitattributes new file mode 100644 index 00000000..176a458f --- /dev/null +++ b/web/src/vendor/benchmark/.gitattributes @@ -0,0 +1 @@ +* text=auto diff --git a/web/src/vendor/benchmark/.gitignore b/web/src/vendor/benchmark/.gitignore new file mode 100644 index 00000000..cdecb6ae --- /dev/null +++ b/web/src/vendor/benchmark/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +node_modules/ +tests/benchmark.air/src/*.js +tests/benchmark.air/bin-debug/ diff --git a/web/src/vendor/benchmark/.npmignore b/web/src/vendor/benchmark/.npmignore new file mode 100644 index 00000000..b9acbef5 --- /dev/null +++ b/web/src/vendor/benchmark/.npmignore @@ -0,0 +1,8 @@ +.* +nano.* +example/ +plugin/ +vendor/ +doc/*.php +test/*.air +test/*.html diff --git a/web/src/vendor/benchmark/LICENSE.txt b/web/src/vendor/benchmark/LICENSE.txt new file mode 100644 index 00000000..e33e63f7 --- /dev/null +++ b/web/src/vendor/benchmark/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright 2010-2012 Mathias Bynens <http://mathiasbynens.be/> +Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/> +Modified by John-David Dalton <http://allyoucanleet.com/> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/web/src/vendor/benchmark/README.md b/web/src/vendor/benchmark/README.md new file mode 100644 index 00000000..62a2d1ae --- /dev/null +++ b/web/src/vendor/benchmark/README.md @@ -0,0 +1,135 @@ +# Benchmark.js <sup>v1.0.0</sup> + +A [robust](http://calendar.perfplanet.com/2010/bulletproof-javascript-benchmarks/ "Bulletproof JavaScript benchmarks") benchmarking library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>, supports high-resolution timers, and returns statistically significant results. As seen on [jsPerf](http://jsperf.com/). + +## Download + + * [Development source](https://raw.github.com/bestiejs/benchmark.js/v1.0.0/benchmark.js) + +## Dive in + +We’ve got [API docs](http://benchmarkjs.com/docs) and [unit tests](http://benchmarkjs.com/tests). + +For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/benchmark.js/wiki/Roadmap). + +## Support + +Benchmark.js has been tested in at least Adobe AIR 3.1, Chrome 5-21, Firefox 1.5-13, IE 6-9, Opera 9.25-12.01, Safari 3-6, Node.js 0.8.6, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5. + +## Installation and usage + +In a browser or Adobe AIR: + +```html +<script src="benchmark.js"></script> +``` + +Optionally, expose Java’s nanosecond timer by adding the `nano` applet to the `<body>`: + +```html +<applet code="nano" archive="nano.jar"></applet> +``` + +Or enable Chrome’s microsecond timer by using the [command line switch](http://peter.sh/experiments/chromium-command-line-switches/#enable-benchmarking): + + --enable-benchmarking + +Via [npm](http://npmjs.org/): + +```bash +npm install benchmark +``` + +In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/): + +```js +var Benchmark = require('benchmark'); +``` + +Optionally, use the [microtime module](https://github.com/wadey/node-microtime) by Wade Simmons: + +```bash +npm install microtime +``` + +In [RingoJS v0.7.0-](http://ringojs.org/): + +```js +var Benchmark = require('benchmark').Benchmark; +``` + +In [Rhino](http://www.mozilla.org/rhino/): + +```js +load('benchmark.js'); +``` + +In an AMD loader like [RequireJS](http://requirejs.org/): + +```js +require({ + 'paths': { + 'benchmark': 'path/to/benchmark' + } +}, +['benchmark'], function(Benchmark) { + console.log(Benchmark.version); +}); + +// or with platform.js +// https://github.com/bestiejs/platform.js +require({ + 'paths': { + 'benchmark': 'path/to/benchmark', + 'platform': 'path/to/platform' + } +}, +['benchmark', 'platform'], function(Benchmark, platform) { + Benchmark.platform = platform; + console.log(Benchmark.platform.name); +}); +``` + +Usage example: + +```js +var suite = new Benchmark.Suite; + +// add tests +suite.add('RegExp#test', function() { + /o/.test('Hello World!'); +}) +.add('String#indexOf', function() { + 'Hello World!'.indexOf('o') > -1; +}) +// add listeners +.on('cycle', function(event) { + console.log(String(event.target)); +}) +.on('complete', function() { + console.log('Fastest is ' + this.filter('fastest').pluck('name')); +}) +// run async +.run({ 'async': true }); + +// logs: +// > RegExp#test x 4,161,532 +-0.99% (59 cycles) +// > String#indexOf x 6,139,623 +-1.00% (131 cycles) +// > Fastest is String#indexOf +``` + +## BestieJS + +Benchmark.js is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation. + +## Authors + +* [Mathias Bynens](http://mathiasbynens.be/) + [](https://twitter.com/mathias "Follow @mathias on Twitter") +* [John-David Dalton](http://allyoucanleet.com/) + [](https://twitter.com/jdalton "Follow @jdalton on Twitter") + +## Contributors + +* [Kit Cambridge](http://kitcambridge.github.com/) + [](https://twitter.com/kitcambridge "Follow @kitcambridge on Twitter") diff --git a/web/src/vendor/benchmark/benchmark.js b/web/src/vendor/benchmark/benchmark.js new file mode 100644 index 00000000..db2c9958 --- /dev/null +++ b/web/src/vendor/benchmark/benchmark.js @@ -0,0 +1,3919 @@ +/*! + * Benchmark.js v1.0.0 <http://benchmarkjs.com/> + * Copyright 2010-2012 Mathias Bynens <http://mths.be/> + * Based on JSLitmus.js, copyright Robert Kieffer <http://broofa.com/> + * Modified by John-David Dalton <http://allyoucanleet.com/> + * Available under MIT license <http://mths.be/mit> + */ +;(function(window, undefined) { + 'use strict'; + + /** Used to assign each benchmark an incrimented id */ + var counter = 0; + + /** Detect DOM document object */ + var doc = isHostType(window, 'document') && document; + + /** Detect free variable `define` */ + var freeDefine = typeof define == 'function' && + typeof define.amd == 'object' && define.amd && define; + + /** Detect free variable `exports` */ + var freeExports = typeof exports == 'object' && exports && + (typeof global == 'object' && global && global == global.global && (window = global), exports); + + /** Detect free variable `require` */ + var freeRequire = typeof require == 'function' && require; + + /** Used to crawl all properties regardless of enumerability */ + var getAllKeys = Object.getOwnPropertyNames; + + /** Used to get property descriptors */ + var getDescriptor = Object.getOwnPropertyDescriptor; + + /** Used in case an object doesn't have its own method */ + var hasOwnProperty = {}.hasOwnProperty; + + /** Used to check if an object is extensible */ + var isExtensible = Object.isExtensible || function() { return true; }; + + /** Used to access Wade Simmons' Node microtime module */ + var microtimeObject = req('microtime'); + + /** Used to access the browser's high resolution timer */ + var perfObject = isHostType(window, 'performance') && performance; + + /** Used to call the browser's high resolution timer */ + var perfName = perfObject && ( + perfObject.now && 'now' || + perfObject.webkitNow && 'webkitNow' + ); + + /** Used to access Node's high resolution timer */ + var processObject = isHostType(window, 'process') && process; + + /** Used to check if an own property is enumerable */ + var propertyIsEnumerable = {}.propertyIsEnumerable; + + /** Used to set property descriptors */ + var setDescriptor = Object.defineProperty; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** Used to prevent a `removeChild` memory leak in IE < 9 */ + var trash = doc && doc.createElement('div'); + + /** Used to integrity check compiled tests */ + var uid = 'uid' + (+new Date); + + /** Used to avoid infinite recursion when methods call each other */ + var calledBy = {}; + + /** Used to avoid hz of Infinity */ + var divisors = { + '1': 4096, + '2': 512, + '3': 64, + '4': 8, + '5': 0 + }; + + /** + * T-Distribution two-tailed critical values for 95% confidence + * http://www.itl.nist.gov/div898/handbook/eda/section3/eda3672.htm + */ + var tTable = { + '1': 12.706,'2': 4.303, '3': 3.182, '4': 2.776, '5': 2.571, '6': 2.447, + '7': 2.365, '8': 2.306, '9': 2.262, '10': 2.228, '11': 2.201, '12': 2.179, + '13': 2.16, '14': 2.145, '15': 2.131, '16': 2.12, '17': 2.11, '18': 2.101, + '19': 2.093, '20': 2.086, '21': 2.08, '22': 2.074, '23': 2.069, '24': 2.064, + '25': 2.06, '26': 2.056, '27': 2.052, '28': 2.048, '29': 2.045, '30': 2.042, + 'infinity': 1.96 + }; + + /** + * Critical Mann-Whitney U-values for 95% confidence + * http://www.saburchill.com/IBbiology/stats/003.html + */ + var uTable = { + '5': [0, 1, 2], + '6': [1, 2, 3, 5], + '7': [1, 3, 5, 6, 8], + '8': [2, 4, 6, 8, 10, 13], + '9': [2, 4, 7, 10, 12, 15, 17], + '10': [3, 5, 8, 11, 14, 17, 20, 23], + '11': [3, 6, 9, 13, 16, 19, 23, 26, 30], + '12': [4, 7, 11, 14, 18, 22, 26, 29, 33, 37], + '13': [4, 8, 12, 16, 20, 24, 28, 33, 37, 41, 45], + '14': [5, 9, 13, 17, 22, 26, 31, 36, 40, 45, 50, 55], + '15': [5, 10, 14, 19, 24, 29, 34, 39, 44, 49, 54, 59, 64], + '16': [6, 11, 15, 21, 26, 31, 37, 42, 47, 53, 59, 64, 70, 75], + '17': [6, 11, 17, 22, 28, 34, 39, 45, 51, 57, 63, 67, 75, 81, 87], + '18': [7, 12, 18, 24, 30, 36, 42, 48, 55, 61, 67, 74, 80, 86, 93, 99], + '19': [7, 13, 19, 25, 32, 38, 45, 52, 58, 65, 72, 78, 85, 92, 99, 106, 113], + '20': [8, 14, 20, 27, 34, 41, 48, 55, 62, 69, 76, 83, 90, 98, 105, 112, 119, 127], + '21': [8, 15, 22, 29, 36, 43, 50, 58, 65, 73, 80, 88, 96, 103, 111, 119, 126, 134, 142], + '22': [9, 16, 23, 30, 38, 45, 53, 61, 69, 77, 85, 93, 101, 109, 117, 125, 133, 141, 150, 158], + '23': [9, 17, 24, 32, 40, 48, 56, 64, 73, 81, 89, 98, 106, 115, 123, 132, 140, 149, 157, 166, 175], + '24': [10, 17, 25, 33, 42, 50, 59, 67, 76, 85, 94, 102, 111, 120, 129, 138, 147, 156, 165, 174, 183, 192], + '25': [10, 18, 27, 35, 44, 53, 62, 71, 80, 89, 98, 107, 117, 126, 135, 145, 154, 163, 173, 182, 192, 201, 211], + '26': [11, 19, 28, 37, 46, 55, 64, 74, 83, 93, 102, 112, 122, 132, 141, 151, 161, 171, 181, 191, 200, 210, 220, 230], + '27': [11, 20, 29, 38, 48, 57, 67, 77, 87, 97, 107, 118, 125, 138, 147, 158, 168, 178, 188, 199, 209, 219, 230, 240, 250], + '28': [12, 21, 30, 40, 50, 60, 70, 80, 90, 101, 111, 122, 132, 143, 154, 164, 175, 186, 196, 207, 218, 228, 239, 250, 261, 272], + '29': [13, 22, 32, 42, 52, 62, 73, 83, 94, 105, 116, 127, 138, 149, 160, 171, 182, 193, 204, 215, 226, 238, 249, 260, 271, 282, 294], + '30': [13, 23, 33, 43, 54, 65, 76, 87, 98, 109, 120, 131, 143, 154, 166, 177, 189, 200, 212, 223, 235, 247, 258, 270, 282, 293, 305, 317] + }; + + /** + * An object used to flag environments/features. + * + * @static + * @memberOf Benchmark + * @type Object + */ + var support = {}; + + (function() { + + /** + * Detect Adobe AIR. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.air = isClassOf(window.runtime, 'ScriptBridgingProxyObject'); + + /** + * Detect if `arguments` objects have the correct internal [[Class]] value. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.argumentsClass = isClassOf(arguments, 'Arguments'); + + /** + * Detect if in a browser environment. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.browser = doc && isHostType(window, 'navigator'); + + /** + * Detect if strings support accessing characters by index. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.charByIndex = + // IE 8 supports indexes on string literals but not string objects + ('x'[0] + Object('x')[0]) == 'xx'; + + /** + * Detect if strings have indexes as own properties. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.charByOwnIndex = + // Narwhal, Rhino, RingoJS, IE 8, and Opera < 10.52 support indexes on + // strings but don't detect them as own properties + support.charByIndex && hasKey('x', '0'); + + /** + * Detect if Java is enabled/exposed. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.java = isClassOf(window.java, 'JavaPackage'); + + /** + * Detect if the Timers API exists. + * + * @memberOf Benchmark.support + * @type Boolean + */ + support.timeout = isHostType(window, 'setTimeout') && isHostType(window, 'clearTimeout'); + + /** + * Detect if functions support decompilation. + * + * @name decompilation + * @memberOf Benchmark.support + * @type Boolean + */ + try { + // Safari 2.x removes commas in object literals + // from Function#toString results + // http://webk.it/11609 + // Firefox 3.6 and Opera 9.25 strip grouping + // parentheses from Function#toString results + // http://bugzil.la/559438 + support.decompilation = Function( + 'return (' + (function(x) { return { 'x': '' + (1 + x) + '', 'y': 0 }; }) + ')' + )()(0).x === '1'; + } catch(e) { + support.decompilation = false; + } + + /** + * Detect ES5+ property descriptor API. + * + * @name descriptors + * @memberOf Benchmark.support + * @type Boolean + */ + try { + var o = {}; + support.descriptors = (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); + } catch(e) { + support.descriptors = false; + } + + /** + * Detect ES5+ Object.getOwnPropertyNames(). + * + * @name getAllKeys + * @memberOf Benchmark.support + * @type Boolean + */ + try { + support.getAllKeys = /\bvalueOf\b/.test(getAllKeys(Object.prototype)); + } catch(e) { + support.getAllKeys = false; + } + + /** + * Detect if own properties are iterated before inherited properties (all but IE < 9). + * + * @name iteratesOwnLast + * @memberOf Benchmark.support + * @type Boolean + */ + support.iteratesOwnFirst = (function() { + var props = []; + function ctor() { this.x = 1; } + ctor.prototype = { 'y': 1 }; + for (var prop in new ctor) { props.push(prop); } + return props[0] == 'x'; + }()); + + /** + * Detect if a node's [[Class]] is resolvable (all but IE < 9) + * and that the JS engine errors when attempting to coerce an object to a + * string without a `toString` property value of `typeof` "function". + * + * @name nodeClass + * @memberOf Benchmark.support + * @type Boolean + */ + try { + support.nodeClass = ({ 'toString': 0 } + '', toString.call(doc || 0) != '[object Object]'); + } catch(e) { + support.nodeClass = true; + } + }()); + + /** + * Timer object used by `clock()` and `Deferred#resolve`. + * + * @private + * @type Object + */ + var timer = { + + /** + * The timer namespace object or constructor. + * + * @private + * @memberOf timer + * @type Function|Object + */ + 'ns': Date, + + /** + * Starts the deferred timer. + * + * @private + * @memberOf timer + * @param {Object} deferred The deferred instance. + */ + 'start': null, // lazy defined in `clock()` + + /** + * Stops the deferred timer. + * + * @private + * @memberOf timer + * @param {Object} deferred The deferred instance. + */ + 'stop': null // lazy defined in `clock()` + }; + + /** Shortcut for inverse results */ + var noArgumentsClass = !support.argumentsClass, + noCharByIndex = !support.charByIndex, + noCharByOwnIndex = !support.charByOwnIndex; + + /** Math shortcuts */ + var abs = Math.abs, + floor = Math.floor, + max = Math.max, + min = Math.min, + pow = Math.pow, + sqrt = Math.sqrt; + + /*--------------------------------------------------------------------------*/ + + /** + * The Benchmark constructor. + * + * @constructor + * @param {String} name A name to identify the benchmark. + * @param {Function|String} fn The test to benchmark. + * @param {Object} [options={}] Options object. + * @example + * + * // basic usage (the `new` operator is optional) + * var bench = new Benchmark(fn); + * + * // or using a name first + * var bench = new Benchmark('foo', fn); + * + * // or with options + * var bench = new Benchmark('foo', fn, { + * + * // displayed by Benchmark#toString if `name` is not available + * 'id': 'xyz', + * + * // called when the benchmark starts running + * 'onStart': onStart, + * + * // called after each run cycle + * 'onCycle': onCycle, + * + * // called when aborted + * 'onAbort': onAbort, + * + * // called when a test errors + * 'onError': onError, + * + * // called when reset + * 'onReset': onReset, + * + * // called when the benchmark completes running + * 'onComplete': onComplete, + * + * // compiled/called before the test loop + * 'setup': setup, + * + * // compiled/called after the test loop + * 'teardown': teardown + * }); + * + * // or name and options + * var bench = new Benchmark('foo', { + * + * // a flag to indicate the benchmark is deferred + * 'defer': true, + * + * // benchmark test function + * 'fn': function(deferred) { + * // call resolve() when the deferred test is finished + * deferred.resolve(); + * } + * }); + * + * // or options only + * var bench = new Benchmark({ + * + * // benchmark name + * 'name': 'foo', + * + * // benchmark test as a string + * 'fn': '[1,2,3,4].sort()' + * }); + * + * // a test's `this` binding is set to the benchmark instance + * var bench = new Benchmark('foo', function() { + * 'My name is '.concat(this.name); // My name is foo + * }); + */ + function Benchmark(name, fn, options) { + var me = this; + + // allow instance creation without the `new` operator + if (me == null || me.constructor != Benchmark) { + return new Benchmark(name, fn, options); + } + // juggle arguments + if (isClassOf(name, 'Object')) { + // 1 argument (options) + options = name; + } + else if (isClassOf(name, 'Function')) { + // 2 arguments (fn, options) + options = fn; + fn = name; + } + else if (isClassOf(fn, 'Object')) { + // 2 arguments (name, options) + options = fn; + fn = null; + me.name = name; + } + else { + // 3 arguments (name, fn [, options]) + me.name = name; + } + setOptions(me, options); + me.id || (me.id = ++counter); + me.fn == null && (me.fn = fn); + me.stats = deepClone(me.stats); + me.times = deepClone(me.times); + } + + /** + * The Deferred constructor. + * + * @constructor + * @memberOf Benchmark + * @param {Object} clone The cloned benchmark instance. + */ + function Deferred(clone) { + var me = this; + if (me == null || me.constructor != Deferred) { + return new Deferred(clone); + } + me.benchmark = clone; + clock(me); + } + + /** + * The Event constructor. + * + * @constructor + * @memberOf Benchmark + * @param {String|Object} type The event type. + */ + function Event(type) { + var me = this; + return (me == null || me.constructor != Event) + ? new Event(type) + : (type instanceof Event) + ? type + : extend(me, { 'timeStamp': +new Date }, typeof type == 'string' ? { 'type': type } : type); + } + + /** + * The Suite constructor. + * + * @constructor + * @memberOf Benchmark + * @param {String} name A name to identify the suite. + * @param {Object} [options={}] Options object. + * @example + * + * // basic usage (the `new` operator is optional) + * var suite = new Benchmark.Suite; + * + * // or using a name first + * var suite = new Benchmark.Suite('foo'); + * + * // or with options + * var suite = new Benchmark.Suite('foo', { + * + * // called when the suite starts running + * 'onStart': onStart, + * + * // called between running benchmarks + * 'onCycle': onCycle, + * + * // called when aborted + * 'onAbort': onAbort, + * + * // called when a test errors + * 'onError': onError, + * + * // called when reset + * 'onReset': onReset, + * + * // called when the suite completes running + * 'onComplete': onComplete + * }); + */ + function Suite(name, options) { + var me = this; + + // allow instance creation without the `new` operator + if (me == null || me.constructor != Suite) { + return new Suite(name, options); + } + // juggle arguments + if (isClassOf(name, 'Object')) { + // 1 argument (options) + options = name; + } else { + // 2 arguments (name [, options]) + me.name = name; + } + setOptions(me, options); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Note: Some array methods have been implemented in plain JavaScript to avoid + * bugs in IE, Opera, Rhino, and Mobile Safari. + * + * IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()` + * functions that fail to remove the last element, `object[0]`, of + * array-like-objects even though the `length` property is set to `0`. + * The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` + * is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. + * + * In Opera < 9.50 and some older/beta Mobile Safari versions using `unshift()` + * generically to augment the `arguments` object will pave the value at index 0 + * without incrimenting the other values's indexes. + * https://github.com/documentcloud/underscore/issues/9 + * + * Rhino and environments it powers, like Narwhal and RingoJS, may have + * buggy Array `concat()`, `reverse()`, `shift()`, `slice()`, `splice()` and + * `unshift()` functions that make sparse arrays non-sparse by assigning the + * undefined indexes a value of undefined. + * https://github.com/mozilla/rhino/commit/702abfed3f8ca043b2636efd31c14ba7552603dd + */ + + /** + * Creates an array containing the elements of the host array followed by the + * elements of each argument in order. + * + * @memberOf Benchmark.Suite + * @returns {Array} The new array. + */ + function concat() { + var value, + j = -1, + length = arguments.length, + result = slice.call(this), + index = result.length; + + while (++j < length) { + value = arguments[j]; + if (isClassOf(value, 'Array')) { + for (var k = 0, l = value.length; k < l; k++, index++) { + if (k in value) { + result[index] = value[k]; + } + } + } else { + result[index++] = value; + } + } + return result; + } + + /** + * Utility function used by `shift()`, `splice()`, and `unshift()`. + * + * @private + * @param {Number} start The index to start inserting elements. + * @param {Number} deleteCount The number of elements to delete from the insert point. + * @param {Array} elements The elements to insert. + * @returns {Array} An array of deleted elements. + */ + function insert(start, deleteCount, elements) { + // `result` should have its length set to the `deleteCount` + // see https://bugs.ecmascript.org/show_bug.cgi?id=332 + var deleteEnd = start + deleteCount, + elementCount = elements ? elements.length : 0, + index = start - 1, + length = start + elementCount, + object = this, + result = Array(deleteCount), + tail = slice.call(object, deleteEnd); + + // delete elements from the array + while (++index < deleteEnd) { + if (index in object) { + result[index - start] = object[index]; + delete object[index]; + } + } + // insert elements + index = start - 1; + while (++index < length) { + object[index] = elements[index - start]; + } + // append tail elements + start = index--; + length = max(0, (object.length >>> 0) - deleteCount + elementCount); + while (++index < length) { + if ((index - start) in tail) { + object[index] = tail[index - start]; + } else if (index in object) { + delete object[index]; + } + } + // delete excess elements + deleteCount = deleteCount > elementCount ? deleteCount - elementCount : 0; + while (deleteCount--) { + index = length + deleteCount; + if (index in object) { + delete object[index]; + } + } + object.length = length; + return result; + } + + /** + * Rearrange the host array's elements in reverse order. + * + * @memberOf Benchmark.Suite + * @returns {Array} The reversed array. + */ + function reverse() { + var upperIndex, + value, + index = -1, + object = Object(this), + length = object.length >>> 0, + middle = floor(length / 2); + + if (length > 1) { + while (++index < middle) { + upperIndex = length - index - 1; + value = upperIndex in object ? object[upperIndex] : uid; + if (index in object) { + object[upperIndex] = object[index]; + } else { + delete object[upperIndex]; + } + if (value != uid) { + object[index] = value; + } else { + delete object[index]; + } + } + } + return object; + } + + /** + * Removes the first element of the host array and returns it. + * + * @memberOf Benchmark.Suite + * @returns {Mixed} The first element of the array. + */ + function shift() { + return insert.call(this, 0, 1)[0]; + } + + /** + * Creates an array of the host array's elements from the start index up to, + * but not including, the end index. + * + * @memberOf Benchmark.Suite + * @param {Number} start The starting index. + * @param {Number} end The end index. + * @returns {Array} The new array. + */ + function slice(start, end) { + var index = -1, + object = Object(this), + length = object.length >>> 0, + result = []; + + start = toInteger(start); + start = start < 0 ? max(length + start, 0) : min(start, length); + start--; + end = end == null ? length : toInteger(end); + end = end < 0 ? max(length + end, 0) : min(end, length); + + while ((++index, ++start) < end) { + if (start in object) { + result[index] = object[start]; + } + } + return result; + } + + /** + * Allows removing a range of elements and/or inserting elements into the + * host array. + * + * @memberOf Benchmark.Suite + * @param {Number} start The start index. + * @param {Number} deleteCount The number of elements to delete. + * @param {Mixed} [val1, val2, ...] values to insert at the `start` index. + * @returns {Array} An array of removed elements. + */ + function splice(start, deleteCount) { + var object = Object(this), + length = object.length >>> 0; + + start = toInteger(start); + start = start < 0 ? max(length + start, 0) : min(start, length); + + // support the de-facto SpiderMonkey extension + // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/splice#Parameters + // https://bugs.ecmascript.org/show_bug.cgi?id=429 + deleteCount = arguments.length == 1 + ? length - start + : min(max(toInteger(deleteCount), 0), length - start); + + return insert.call(object, start, deleteCount, slice.call(arguments, 2)); + } + + /** + * Converts the specified `value` to an integer. + * + * @private + * @param {Mixed} value The value to convert. + * @returns {Number} The resulting integer. + */ + function toInteger(value) { + value = +value; + return value === 0 || !isFinite(value) ? value || 0 : value - (value % 1); + } + + /** + * Appends arguments to the host array. + * + * @memberOf Benchmark.Suite + * @returns {Number} The new length. + */ + function unshift() { + var object = Object(this); + insert.call(object, 0, 0, arguments); + return object.length; + } + + /*--------------------------------------------------------------------------*/ + + /** + * A generic `Function#bind` like method. + * + * @private + * @param {Function} fn The function to be bound to `thisArg`. + * @param {Mixed} thisArg The `this` binding for the given function. + * @returns {Function} The bound function. + */ + function bind(fn, thisArg) { + return function() { fn.apply(thisArg, arguments); }; + } + + /** + * Creates a function from the given arguments string and body. + * + * @private + * @param {String} args The comma separated function arguments. + * @param {String} body The function body. + * @returns {Function} The new function. + */ + function createFunction() { + // lazy define + createFunction = function(args, body) { + var result, + anchor = freeDefine ? define.amd : Benchmark, + prop = uid + 'createFunction'; + + runScript((freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '=function(' + args + '){' + body + '}'); + result = anchor[prop]; + delete anchor[prop]; + return result; + }; + // fix JaegerMonkey bug + // http://bugzil.la/639720 + createFunction = support.browser && (createFunction('', 'return"' + uid + '"') || noop)() == uid ? createFunction : Function; + return createFunction.apply(null, arguments); + } + + /** + * Delay the execution of a function based on the benchmark's `delay` property. + * + * @private + * @param {Object} bench The benchmark instance. + * @param {Object} fn The function to execute. + */ + function delay(bench, fn) { + bench._timerId = setTimeout(fn, bench.delay * 1e3); + } + + /** + * Destroys the given element. + * + * @private + * @param {Element} element The element to destroy. + */ + function destroyElement(element) { + trash.appendChild(element); + trash.innerHTML = ''; + } + + /** + * Iterates over an object's properties, executing the `callback` for each. + * Callbacks may terminate the loop by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} callback The function executed per own property. + * @param {Object} options The options object. + * @returns {Object} Returns the object iterated over. + */ + function forProps() { + var forShadowed, + skipSeen, + forArgs = true, + shadowed = ['constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']; + + (function(enumFlag, key) { + // must use a non-native constructor to catch the Safari 2 issue + function Klass() { this.valueOf = 0; }; + Klass.prototype.valueOf = 0; + // check various for-in bugs + for (key in new Klass) { + enumFlag += key == 'valueOf' ? 1 : 0; + } + // check if `arguments` objects have non-enumerable indexes + for (key in arguments) { + key == '0' && (forArgs = false); + } + // Safari 2 iterates over shadowed properties twice + // http://replay.waybackmachine.org/20090428222941/http://tobielangel.com/2007/1/29/for-in-loop-broken-in-safari/ + skipSeen = enumFlag == 2; + // IE < 9 incorrectly makes an object's properties non-enumerable if they have + // the same name as other non-enumerable properties in its prototype chain. + forShadowed = !enumFlag; + }(0)); + + // lazy define + forProps = function(object, callback, options) { + options || (options = {}); + + var result = object; + object = Object(object); + + var ctor, + key, + keys, + skipCtor, + done = !result, + which = options.which, + allFlag = which == 'all', + index = -1, + iteratee = object, + length = object.length, + ownFlag = allFlag || which == 'own', + seen = {}, + skipProto = isClassOf(object, 'Function'), + thisArg = options.bind; + + if (thisArg !== undefined) { + callback = bind(callback, thisArg); + } + // iterate all properties + if (allFlag && support.getAllKeys) { + for (index = 0, keys = getAllKeys(object), length = keys.length; index < length; index++) { + key = keys[index]; + if (callback(object[key], key, object) === false) { + break; + } + } + } + // else iterate only enumerable properties + else { + for (key in object) { + // Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 + // (if the prototype or a property on the prototype has been set) + // incorrectly set a function's `prototype` property [[Enumerable]] value + // to `true`. Because of this we standardize on skipping the `prototype` + // property of functions regardless of their [[Enumerable]] value. + if ((done = + !(skipProto && key == 'prototype') && + !(skipSeen && (hasKey(seen, key) || !(seen[key] = true))) && + (!ownFlag || ownFlag && hasKey(object, key)) && + callback(object[key], key, object) === false)) { + break; + } + } + // in IE < 9 strings don't support accessing characters by index + if (!done && (forArgs && isArguments(object) || + ((noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String') && + (iteratee = noCharByIndex ? object.split('') : object)))) { + while (++index < length) { + if ((done = + callback(iteratee[index], String(index), object) === false)) { + break; + } + } + } + if (!done && forShadowed) { + // Because IE < 9 can't set the `[[Enumerable]]` attribute of an existing + // property and the `constructor` property of a prototype defaults to + // non-enumerable, we manually skip the `constructor` property when we + // think we are iterating over a `prototype` object. + ctor = object.constructor; + skipCtor = ctor && ctor.prototype && ctor.prototype.constructor === ctor; + for (index = 0; index < 7; index++) { + key = shadowed[index]; + if (!(skipCtor && key == 'constructor') && + hasKey(object, key) && + callback(object[key], key, object) === false) { + break; + } + } + } + } + return result; + }; + return forProps.apply(null, arguments); + } + + /** + * Gets the name of the first argument from a function's source. + * + * @private + * @param {Function} fn The function. + * @returns {String} The argument name. + */ + function getFirstArgument(fn) { + return (!hasKey(fn, 'toString') && + (/^[\s(]*function[^(]*\(([^\s,)]+)/.exec(fn) || 0)[1]) || ''; + } + + /** + * Computes the arithmetic mean of a sample. + * + * @private + * @param {Array} sample The sample. + * @returns {Number} The mean. + */ + function getMean(sample) { + return reduce(sample, function(sum, x) { + return sum + x; + }) / sample.length || 0; + } + + /** + * Gets the source code of a function. + * + * @private + * @param {Function} fn The function. + * @param {String} altSource A string used when a function's source code is unretrievable. + * @returns {String} The function's source code. + */ + function getSource(fn, altSource) { + var result = altSource; + if (isStringable(fn)) { + result = String(fn); + } else if (support.decompilation) { + // escape the `{` for Firefox 1 + result = (/^[^{]+\{([\s\S]*)}\s*$/.exec(fn) || 0)[1]; + } + // trim string + result = (result || '').replace(/^\s+|\s+$/g, ''); + + // detect strings containing only the "use strict" directive + return /^(?:\/\*+[\w|\W]*?\*\/|\/\/.*?[\n\r\u2028\u2029]|\s)*(["'])use strict\1;?$/.test(result) + ? '' + : result; + } + + /** + * Checks if a value is an `arguments` object. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the value is an `arguments` object, else `false`. + */ + function isArguments() { + // lazy define + isArguments = function(value) { + return toString.call(value) == '[object Arguments]'; + }; + if (noArgumentsClass) { + isArguments = function(value) { + return hasKey(value, 'callee') && + !(propertyIsEnumerable && propertyIsEnumerable.call(value, 'callee')); + }; + } + return isArguments(arguments[0]); + } + + /** + * Checks if an object is of the specified class. + * + * @private + * @param {Mixed} value The value to check. + * @param {String} name The name of the class. + * @returns {Boolean} Returns `true` if the value is of the specified class, else `false`. + */ + function isClassOf(value, name) { + return value != null && toString.call(value) == '[object ' + name + ']'; + } + + /** + * Host objects can return type values that are different from their actual + * data type. The objects we are concerned with usually return non-primitive + * types of object, function, or unknown. + * + * @private + * @param {Mixed} object The owner of the property. + * @param {String} property The property to check. + * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. + */ + function isHostType(object, property) { + var type = object != null ? typeof object[property] : 'number'; + return !/^(?:boolean|number|string|undefined)$/.test(type) && + (type == 'object' ? !!object[property] : true); + } + + /** + * Checks if a given `value` is an object created by the `Object` constructor + * assuming objects created by the `Object` constructor have no inherited + * enumerable properties and that there are no `Object.prototype` extensions. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a plain `Object` object, else `false`. + */ + function isPlainObject(value) { + // avoid non-objects and false positives for `arguments` objects in IE < 9 + var result = false; + if (!(value && typeof value == 'object') || isArguments(value)) { + return result; + } + // IE < 9 presents DOM nodes as `Object` objects except they have `toString` + // methods that are `typeof` "string" and still can coerce nodes to strings. + // Also check that the constructor is `Object` (i.e. `Object instanceof Object`) + var ctor = value.constructor; + if ((support.nodeClass || !(typeof value.toString != 'function' && typeof (value + '') == 'string')) && + (!isClassOf(ctor, 'Function') || ctor instanceof ctor)) { + // In most environments an object's own properties are iterated before + // its inherited properties. If the last iterated property is an object's + // own property then there are no inherited enumerable properties. + if (support.iteratesOwnFirst) { + forProps(value, function(subValue, subKey) { + result = subKey; + }); + return result === false || hasKey(value, result); + } + // IE < 9 iterates inherited properties before own properties. If the first + // iterated property is an object's own property then there are no inherited + // enumerable properties. + forProps(value, function(subValue, subKey) { + result = !hasKey(value, subKey); + return false; + }); + return result === false; + } + return result; + } + + /** + * Checks if a value can be safely coerced to a string. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the value can be coerced, else `false`. + */ + function isStringable(value) { + return hasKey(value, 'toString') || isClassOf(value, 'String'); + } + + /** + * Wraps a function and passes `this` to the original function as the + * first argument. + * + * @private + * @param {Function} fn The function to be wrapped. + * @returns {Function} The new function. + */ + function methodize(fn) { + return function() { + var args = [this]; + args.push.apply(args, arguments); + return fn.apply(null, args); + }; + } + + /** + * A no-operation function. + * + * @private + */ + function noop() { + // no operation performed + } + + /** + * A wrapper around require() to suppress `module missing` errors. + * + * @private + * @param {String} id The module id. + * @returns {Mixed} The exported module or `null`. + */ + function req(id) { + try { + var result = freeExports && freeRequire(id); + } catch(e) { } + return result || null; + } + + /** + * Runs a snippet of JavaScript via script injection. + * + * @private + * @param {String} code The code to run. + */ + function runScript(code) { + var anchor = freeDefine ? define.amd : Benchmark, + script = doc.createElement('script'), + sibling = doc.getElementsByTagName('script')[0], + parent = sibling.parentNode, + prop = uid + 'runScript', + prefix = '(' + (freeDefine ? 'define.amd.' : 'Benchmark.') + prop + '||function(){})();'; + + // Firefox 2.0.0.2 cannot use script injection as intended because it executes + // asynchronously, but that's OK because script injection is only used to avoid + // the previously commented JaegerMonkey bug. + try { + // remove the inserted script *before* running the code to avoid differences + // in the expected script element count/order of the document. + script.appendChild(doc.createTextNode(prefix + code)); + anchor[prop] = function() { destroyElement(script); }; + } catch(e) { + parent = parent.cloneNode(false); + sibling = null; + script.text = code; + } + parent.insertBefore(script, sibling); + delete anchor[prop]; + } + + /** + * A helper function for setting options/event handlers. + * + * @private + * @param {Object} bench The benchmark instance. + * @param {Object} [options={}] Options object. + */ + function setOptions(bench, options) { + options = extend({}, bench.constructor.options, options); + bench.options = forOwn(options, function(value, key) { + if (value != null) { + // add event listeners + if (/^on[A-Z]/.test(key)) { + forEach(key.split(' '), function(key) { + bench.on(key.slice(2).toLowerCase(), value); + }); + } else if (!hasKey(bench, key)) { + bench[key] = deepClone(value); + } + } + }); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Handles cycling/completing the deferred benchmark. + * + * @memberOf Benchmark.Deferred + */ + function resolve() { + var me = this, + clone = me.benchmark, + bench = clone._original; + + if (bench.aborted) { + // cycle() -> clone cycle/complete event -> compute()'s invoked bench.run() cycle/complete + me.teardown(); + clone.running = false; + cycle(me); + } + else if (++me.cycles < clone.count) { + // continue the test loop + if (support.timeout) { + // use setTimeout to avoid a call stack overflow if called recursively + setTimeout(function() { clone.compiled.call(me, timer); }, 0); + } else { + clone.compiled.call(me, timer); + } + } + else { + timer.stop(me); + me.teardown(); + delay(clone, function() { cycle(me); }); + } + } + + /*--------------------------------------------------------------------------*/ + + /** + * A deep clone utility. + * + * @static + * @memberOf Benchmark + * @param {Mixed} value The value to clone. + * @returns {Mixed} The cloned value. + */ + function deepClone(value) { + var accessor, + circular, + clone, + ctor, + descriptor, + extensible, + key, + length, + markerKey, + parent, + result, + source, + subIndex, + data = { 'value': value }, + index = 0, + marked = [], + queue = { 'length': 0 }, + unmarked = []; + + /** + * An easily detectable decorator for cloned values. + */ + function Marker(object) { + this.raw = object; + } + + /** + * The callback used by `forProps()`. + */ + function forPropsCallback(subValue, subKey) { + // exit early to avoid cloning the marker + if (subValue && subValue.constructor == Marker) { + return; + } + // add objects to the queue + if (subValue === Object(subValue)) { + queue[queue.length++] = { 'key': subKey, 'parent': clone, 'source': value }; + } + // assign non-objects + else { + try { + // will throw an error in strict mode if the property is read-only + clone[subKey] = subValue; + } catch(e) { } + } + } + + /** + * Gets an available marker key for the given object. + */ + function getMarkerKey(object) { + // avoid collisions with existing keys + var result = uid; + while (object[result] && object[result].constructor != Marker) { + result += 1; + } + return result; + } + + do { + key = data.key; + parent = data.parent; + source = data.source; + clone = value = source ? source[key] : data.value; + accessor = circular = descriptor = false; + + // create a basic clone to filter out functions, DOM elements, and + // other non `Object` objects + if (value === Object(value)) { + // use custom deep clone function if available + if (isClassOf(value.deepClone, 'Function')) { + clone = value.deepClone(); + } else { + ctor = value.constructor; + switch (toString.call(value)) { + case '[object Array]': + clone = new ctor(value.length); + break; + + case '[object Boolean]': + clone = new ctor(value == true); + break; + + case '[object Date]': + clone = new ctor(+value); + break; + + case '[object Object]': + isPlainObject(value) && (clone = {}); + break; + + case '[object Number]': + case '[object String]': + clone = new ctor(value); + break; + + case '[object RegExp]': + clone = ctor(value.source, + (value.global ? 'g' : '') + + (value.ignoreCase ? 'i' : '') + + (value.multiline ? 'm' : '')); + } + } + // continue clone if `value` doesn't have an accessor descriptor + // http://es5.github.com/#x8.10.1 + if (clone && clone != value && + !(descriptor = source && support.descriptors && getDescriptor(source, key), + accessor = descriptor && (descriptor.get || descriptor.set))) { + // use an existing clone (circular reference) + if ((extensible = isExtensible(value))) { + markerKey = getMarkerKey(value); + if (value[markerKey]) { + circular = clone = value[markerKey].raw; + } + } else { + // for frozen/sealed objects + for (subIndex = 0, length = unmarked.length; subIndex < length; subIndex++) { + data = unmarked[subIndex]; + if (data.object === value) { + circular = clone = data.clone; + break; + } + } + } + if (!circular) { + // mark object to allow quickly detecting circular references and tie it to its clone + if (extensible) { + value[markerKey] = new Marker(clone); + marked.push({ 'key': markerKey, 'object': value }); + } else { + // for frozen/sealed objects + unmarked.push({ 'clone': clone, 'object': value }); + } + // iterate over object properties + forProps(value, forPropsCallback, { 'which': 'all' }); + } + } + } + if (parent) { + // for custom property descriptors + if (accessor || (descriptor && !(descriptor.configurable && descriptor.enumerable && descriptor.writable))) { + if ('value' in descriptor) { + descriptor.value = clone; + } + setDescriptor(parent, key, descriptor); + } + // for default property descriptors + else { + parent[key] = clone; + } + } else { + result = clone; + } + } while ((data = queue[index++])); + + // remove markers + for (index = 0, length = marked.length; index < length; index++) { + data = marked[index]; + delete data.object[data.key]; + } + return result; + } + + /** + * An iteration utility for arrays and objects. + * Callbacks may terminate the loop by explicitly returning `false`. + * + * @static + * @memberOf Benchmark + * @param {Array|Object} object The object to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} thisArg The `this` binding for the callback. + * @returns {Array|Object} Returns the object iterated over. + */ + function each(object, callback, thisArg) { + var result = object; + object = Object(object); + + var fn = callback, + index = -1, + length = object.length, + isSnapshot = !!(object.snapshotItem && (length = object.snapshotLength)), + isSplittable = (noCharByIndex || noCharByOwnIndex) && isClassOf(object, 'String'), + isConvertable = isSnapshot || isSplittable || 'item' in object, + origObject = object; + + // in Opera < 10.5 `hasKey(object, 'length')` returns `false` for NodeLists + if (length === length >>> 0) { + if (isConvertable) { + // the third argument of the callback is the original non-array object + callback = function(value, index) { + return fn.call(this, value, index, origObject); + }; + // in IE < 9 strings don't support accessing characters by index + if (isSplittable) { + object = object.split(''); + } else { + object = []; + while (++index < length) { + // in Safari 2 `index in object` is always `false` for NodeLists + object[index] = isSnapshot ? result.snapshotItem(index) : result[index]; + } + } + } + forEach(object, callback, thisArg); + } else { + forOwn(object, callback, thisArg); + } + return result; + } + + /** + * Copies enumerable properties from the source(s) object to the destination object. + * + * @static + * @memberOf Benchmark + * @param {Object} destination The destination object. + * @param {Object} [source={}] The source object. + * @returns {Object} The destination object. + */ + function extend(destination, source) { + // Chrome < 14 incorrectly sets `destination` to `undefined` when we `delete arguments[0]` + // http://code.google.com/p/v8/issues/detail?id=839 + var result = destination; + delete arguments[0]; + + forEach(arguments, function(source) { + forProps(source, function(value, key) { + result[key] = value; + }); + }); + return result; + } + + /** + * A generic `Array#filter` like method. + * + * @static + * @memberOf Benchmark + * @param {Array} array The array to iterate over. + * @param {Function|String} callback The function/alias called per iteration. + * @param {Mixed} thisArg The `this` binding for the callback. + * @returns {Array} A new array of values that passed callback filter. + * @example + * + * // get odd numbers + * Benchmark.filter([1, 2, 3, 4, 5], function(n) { + * return n % 2; + * }); // -> [1, 3, 5]; + * + * // get fastest benchmarks + * Benchmark.filter(benches, 'fastest'); + * + * // get slowest benchmarks + * Benchmark.filter(benches, 'slowest'); + * + * // get benchmarks that completed without erroring + * Benchmark.filter(benches, 'successful'); + */ + function filter(array, callback, thisArg) { + var result; + + if (callback == 'successful') { + // callback to exclude those that are errored, unrun, or have hz of Infinity + callback = function(bench) { return bench.cycles && isFinite(bench.hz); }; + } + else if (callback == 'fastest' || callback == 'slowest') { + // get successful, sort by period + margin of error, and filter fastest/slowest + result = filter(array, 'successful').sort(function(a, b) { + a = a.stats; b = b.stats; + return (a.mean + a.moe > b.mean + b.moe ? 1 : -1) * (callback == 'fastest' ? 1 : -1); + }); + result = filter(result, function(bench) { + return result[0].compare(bench) == 0; + }); + } + return result || reduce(array, function(result, value, index) { + return callback.call(thisArg, value, index, array) ? (result.push(value), result) : result; + }, []); + } + + /** + * A generic `Array#forEach` like method. + * Callbacks may terminate the loop by explicitly returning `false`. + * + * @static + * @memberOf Benchmark + * @param {Array} array The array to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} thisArg The `this` binding for the callback. + * @returns {Array} Returns the array iterated over. + */ + function forEach(array, callback, thisArg) { + var index = -1, + length = (array = Object(array)).length >>> 0; + + if (thisArg !== undefined) { + callback = bind(callback, thisArg); + } + while (++index < length) { + if (index in array && + callback(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * Iterates over an object's own properties, executing the `callback` for each. + * Callbacks may terminate the loop by explicitly returning `false`. + * + * @static + * @memberOf Benchmark + * @param {Object} object The object to iterate over. + * @param {Function} callback The function executed per own property. + * @param {Mixed} thisArg The `this` binding for the callback. + * @returns {Object} Returns the object iterated over. + */ + function forOwn(object, callback, thisArg) { + return forProps(object, callback, { 'bind': thisArg, 'which': 'own' }); + } + + /** + * Converts a number to a more readable comma-separated string representation. + * + * @static + * @memberOf Benchmark + * @param {Number} number The number to convert. + * @returns {String} The more readable string representation. + */ + function formatNumber(number) { + number = String(number).split('.'); + return number[0].replace(/(?=(?:\d{3})+$)(?!\b)/g, ',') + + (number[1] ? '.' + number[1] : ''); + } + + /** + * Checks if an object has the specified key as a direct property. + * + * @static + * @memberOf Benchmark + * @param {Object} object The object to check. + * @param {String} key The key to check for. + * @returns {Boolean} Returns `true` if key is a direct property, else `false`. + */ + function hasKey() { + // lazy define for worst case fallback (not as accurate) + hasKey = function(object, key) { + var parent = object != null && (object.constructor || Object).prototype; + return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); + }; + // for modern browsers + if (isClassOf(hasOwnProperty, 'Function')) { + hasKey = function(object, key) { + return object != null && hasOwnProperty.call(object, key); + }; + } + // for Safari 2 + else if ({}.__proto__ == Object.prototype) { + hasKey = function(object, key) { + var result = false; + if (object != null) { + object = Object(object); + object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; + } + return result; + }; + } + return hasKey.apply(this, arguments); + } + + /** + * A generic `Array#indexOf` like method. + * + * @static + * @memberOf Benchmark + * @param {Array} array The array to iterate over. + * @param {Mixed} value The value to search for. + * @param {Number} [fromIndex=0] The index to start searching from. + * @returns {Number} The index of the matched value or `-1`. + */ + function indexOf(array, value, fromIndex) { + var index = toInteger(fromIndex), + length = (array = Object(array)).length >>> 0; + + index = (index < 0 ? max(0, length + index) : index) - 1; + while (++index < length) { + if (index in array && value === array[index]) { + return index; + } + } + return -1; + } + + /** + * Modify a string by replacing named tokens with matching object property values. + * + * @static + * @memberOf Benchmark + * @param {String} string The string to modify. + * @param {Object} object The template object. + * @returns {String} The modified string. + */ + function interpolate(string, object) { + forOwn(object, function(value, key) { + // escape regexp special characters in `key` + string = string.replace(RegExp('#\\{' + key.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1') + '\\}', 'g'), value); + }); + return string; + } + + /** + * Invokes a method on all items in an array. + * + * @static + * @memberOf Benchmark + * @param {Array} benches Array of benchmarks to iterate over. + * @param {String|Object} name The name of the method to invoke OR options object. + * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. + * @returns {Array} A new array of values returned from each method invoked. + * @example + * + * // invoke `reset` on all benchmarks + * Benchmark.invoke(benches, 'reset'); + * + * // invoke `emit` with arguments + * Benchmark.invoke(benches, 'emit', 'complete', listener); + * + * // invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks + * Benchmark.invoke(benches, { + * + * // invoke the `run` method + * 'name': 'run', + * + * // pass a single argument + * 'args': true, + * + * // treat as queue, removing benchmarks from front of `benches` until empty + * 'queued': true, + * + * // called before any benchmarks have been invoked. + * 'onStart': onStart, + * + * // called between invoking benchmarks + * 'onCycle': onCycle, + * + * // called after all benchmarks have been invoked. + * 'onComplete': onComplete + * }); + */ + function invoke(benches, name) { + var args, + bench, + queued, + index = -1, + eventProps = { 'currentTarget': benches }, + options = { 'onStart': noop, 'onCycle': noop, 'onComplete': noop }, + result = map(benches, function(bench) { return bench; }); + + /** + * Invokes the method of the current object and if synchronous, fetches the next. + */ + function execute() { + var listeners, + async = isAsync(bench); + + if (async) { + // use `getNext` as the first listener + bench.on('complete', getNext); + listeners = bench.events.complete; + listeners.splice(0, 0, listeners.pop()); + } + // execute method + result[index] = isClassOf(bench && bench[name], 'Function') ? bench[name].apply(bench, args) : undefined; + // if synchronous return true until finished + return !async && getNext(); + } + + /** + * Fetches the next bench or executes `onComplete` callback. + */ + function getNext(event) { + var cycleEvent, + last = bench, + async = isAsync(last); + + if (async) { + last.off('complete', getNext); + last.emit('complete'); + } + // emit "cycle" event + eventProps.type = 'cycle'; + eventProps.target = last; + cycleEvent = Event(eventProps); + options.onCycle.call(benches, cycleEvent); + + // choose next benchmark if not exiting early + if (!cycleEvent.aborted && raiseIndex() !== false) { + bench = queued ? benches[0] : result[index]; + if (isAsync(bench)) { + delay(bench, execute); + } + else if (async) { + // resume execution if previously asynchronous but now synchronous + while (execute()) { } + } + else { + // continue synchronous execution + return true; + } + } else { + // emit "complete" event + eventProps.type = 'complete'; + options.onComplete.call(benches, Event(eventProps)); + } + // When used as a listener `event.aborted = true` will cancel the rest of + // the "complete" listeners because they were already called above and when + // used as part of `getNext` the `return false` will exit the execution while-loop. + if (event) { + event.aborted = true; + } else { + return false; + } + } + + /** + * Checks if invoking `Benchmark#run` with asynchronous cycles. + */ + function isAsync(object) { + // avoid using `instanceof` here because of IE memory leak issues with host objects + var async = args[0] && args[0].async; + return Object(object).constructor == Benchmark && name == 'run' && + ((async == null ? object.options.async : async) && support.timeout || object.defer); + } + + /** + * Raises `index` to the next defined index or returns `false`. + */ + function raiseIndex() { + var length = result.length; + if (queued) { + // if queued remove the previous bench and subsequent skipped non-entries + do { + ++index > 0 && shift.call(benches); + } while ((length = benches.length) && !('0' in benches)); + } + else { + while (++index < length && !(index in result)) { } + } + // if we reached the last index then return `false` + return (queued ? length : index < length) ? index : (index = false); + } + + // juggle arguments + if (isClassOf(name, 'String')) { + // 2 arguments (array, name) + args = slice.call(arguments, 2); + } else { + // 2 arguments (array, options) + options = extend(options, name); + name = options.name; + args = isClassOf(args = 'args' in options ? options.args : [], 'Array') ? args : [args]; + queued = options.queued; + } + + // start iterating over the array + if (raiseIndex() !== false) { + // emit "start" event + bench = result[index]; + eventProps.type = 'start'; + eventProps.target = bench; + options.onStart.call(benches, Event(eventProps)); + + // end early if the suite was aborted in an "onStart" listener + if (benches.aborted && benches.constructor == Suite && name == 'run') { + // emit "cycle" event + eventProps.type = 'cycle'; + options.onCycle.call(benches, Event(eventProps)); + // emit "complete" event + eventProps.type = 'complete'; + options.onComplete.call(benches, Event(eventProps)); + } + // else start + else { + if (isAsync(bench)) { + delay(bench, execute); + } else { + while (execute()) { } + } + } + } + return result; + } + + /** + * Creates a string of joined array values or object key-value pairs. + * + * @static + * @memberOf Benchmark + * @param {Array|Object} object The object to operate on. + * @param {String} [separator1=','] The separator used between key-value pairs. + * @param {String} [separator2=': '] The separator used between keys and values. + * @returns {String} The joined result. + */ + function join(object, separator1, separator2) { + var result = [], + length = (object = Object(object)).length, + arrayLike = length === length >>> 0; + + separator2 || (separator2 = ': '); + each(object, function(value, key) { + result.push(arrayLike ? value : key + separator2 + value); + }); + return result.join(separator1 || ','); + } + + /** + * A generic `Array#map` like method. + * + * @static + * @memberOf Benchmark + * @param {Array} array The array to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} thisArg The `this` binding for the callback. + * @returns {Array} A new array of values returned by the callback. + */ + function map(array, callback, thisArg) { + return reduce(array, function(result, value, index) { + result[index] = callback.call(thisArg, value, index, array); + return result; + }, Array(Object(array).length >>> 0)); + } + + /** + * Retrieves the value of a specified property from all items in an array. + * + * @static + * @memberOf Benchmark + * @param {Array} array The array to iterate over. + * @param {String} property The property to pluck. + * @returns {Array} A new array of property values. + */ + function pluck(array, property) { + return map(array, function(object) { + return object == null ? undefined : object[property]; + }); + } + + /** + * A generic `Array#reduce` like method. + * + * @static + * @memberOf Benchmark + * @param {Array} array The array to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} accumulator Initial value of the accumulator. + * @returns {Mixed} The accumulator. + */ + function reduce(array, callback, accumulator) { + var noaccum = arguments.length < 3; + forEach(array, function(value, index) { + accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, array); + }); + return accumulator; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Aborts all benchmarks in the suite. + * + * @name abort + * @memberOf Benchmark.Suite + * @returns {Object} The suite instance. + */ + function abortSuite() { + var event, + me = this, + resetting = calledBy.resetSuite; + + if (me.running) { + event = Event('abort'); + me.emit(event); + if (!event.cancelled || resetting) { + // avoid infinite recursion + calledBy.abortSuite = true; + me.reset(); + delete calledBy.abortSuite; + + if (!resetting) { + me.aborted = true; + invoke(me, 'abort'); + } + } + } + return me; + } + + /** + * Adds a test to the benchmark suite. + * + * @memberOf Benchmark.Suite + * @param {String} name A name to identify the benchmark. + * @param {Function|String} fn The test to benchmark. + * @param {Object} [options={}] Options object. + * @returns {Object} The benchmark instance. + * @example + * + * // basic usage + * suite.add(fn); + * + * // or using a name first + * suite.add('foo', fn); + * + * // or with options + * suite.add('foo', fn, { + * 'onCycle': onCycle, + * 'onComplete': onComplete + * }); + * + * // or name and options + * suite.add('foo', { + * 'fn': fn, + * 'onCycle': onCycle, + * 'onComplete': onComplete + * }); + * + * // or options only + * suite.add({ + * 'name': 'foo', + * 'fn': fn, + * 'onCycle': onCycle, + * 'onComplete': onComplete + * }); + */ + function add(name, fn, options) { + var me = this, + bench = Benchmark(name, fn, options), + event = Event({ 'type': 'add', 'target': bench }); + + if (me.emit(event), !event.cancelled) { + me.push(bench); + } + return me; + } + + /** + * Creates a new suite with cloned benchmarks. + * + * @name clone + * @memberOf Benchmark.Suite + * @param {Object} options Options object to overwrite cloned options. + * @returns {Object} The new suite instance. + */ + function cloneSuite(options) { + var me = this, + result = new me.constructor(extend({}, me.options, options)); + + // copy own properties + forOwn(me, function(value, key) { + if (!hasKey(result, key)) { + result[key] = value && isClassOf(value.clone, 'Function') + ? value.clone() + : deepClone(value); + } + }); + return result; + } + + /** + * An `Array#filter` like method. + * + * @name filter + * @memberOf Benchmark.Suite + * @param {Function|String} callback The function/alias called per iteration. + * @returns {Object} A new suite of benchmarks that passed callback filter. + */ + function filterSuite(callback) { + var me = this, + result = new me.constructor; + + result.push.apply(result, filter(me, callback)); + return result; + } + + /** + * Resets all benchmarks in the suite. + * + * @name reset + * @memberOf Benchmark.Suite + * @returns {Object} The suite instance. + */ + function resetSuite() { + var event, + me = this, + aborting = calledBy.abortSuite; + + if (me.running && !aborting) { + // no worries, `resetSuite()` is called within `abortSuite()` + calledBy.resetSuite = true; + me.abort(); + delete calledBy.resetSuite; + } + // reset if the state has changed + else if ((me.aborted || me.running) && + (me.emit(event = Event('reset')), !event.cancelled)) { + me.running = false; + if (!aborting) { + invoke(me, 'reset'); + } + } + return me; + } + + /** + * Runs the suite. + * + * @name run + * @memberOf Benchmark.Suite + * @param {Object} [options={}] Options object. + * @returns {Object} The suite instance. + * @example + * + * // basic usage + * suite.run(); + * + * // or with options + * suite.run({ 'async': true, 'queued': true }); + */ + function runSuite(options) { + var me = this; + + me.reset(); + me.running = true; + options || (options = {}); + + invoke(me, { + 'name': 'run', + 'args': options, + 'queued': options.queued, + 'onStart': function(event) { + me.emit(event); + }, + 'onCycle': function(event) { + var bench = event.target; + if (bench.error) { + me.emit({ 'type': 'error', 'target': bench }); + } + me.emit(event); + event.aborted = me.aborted; + }, + 'onComplete': function(event) { + me.running = false; + me.emit(event); + } + }); + return me; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Executes all registered listeners of the specified event type. + * + * @memberOf Benchmark, Benchmark.Suite + * @param {String|Object} type The event type or object. + * @returns {Mixed} Returns the return value of the last listener executed. + */ + function emit(type) { + var listeners, + me = this, + event = Event(type), + events = me.events, + args = (arguments[0] = event, arguments); + + event.currentTarget || (event.currentTarget = me); + event.target || (event.target = me); + delete event.result; + + if (events && (listeners = hasKey(events, event.type) && events[event.type])) { + forEach(listeners.slice(), function(listener) { + if ((event.result = listener.apply(me, args)) === false) { + event.cancelled = true; + } + return !event.aborted; + }); + } + return event.result; + } + + /** + * Returns an array of event listeners for a given type that can be manipulated + * to add or remove listeners. + * + * @memberOf Benchmark, Benchmark.Suite + * @param {String} type The event type. + * @returns {Array} The listeners array. + */ + function listeners(type) { + var me = this, + events = me.events || (me.events = {}); + + return hasKey(events, type) ? events[type] : (events[type] = []); + } + + /** + * Unregisters a listener for the specified event type(s), + * or unregisters all listeners for the specified event type(s), + * or unregisters all listeners for all event types. + * + * @memberOf Benchmark, Benchmark.Suite + * @param {String} [type] The event type. + * @param {Function} [listener] The function to unregister. + * @returns {Object} The benchmark instance. + * @example + * + * // unregister a listener for an event type + * bench.off('cycle', listener); + * + * // unregister a listener for multiple event types + * bench.off('start cycle', listener); + * + * // unregister all listeners for an event type + * bench.off('cycle'); + * + * // unregister all listeners for multiple event types + * bench.off('start cycle complete'); + * + * // unregister all listeners for all event types + * bench.off(); + */ + function off(type, listener) { + var me = this, + events = me.events; + + events && each(type ? type.split(' ') : events, function(listeners, type) { + var index; + if (typeof listeners == 'string') { + type = listeners; + listeners = hasKey(events, type) && events[type]; + } + if (listeners) { + if (listener) { + index = indexOf(listeners, listener); + if (index > -1) { + listeners.splice(index, 1); + } + } else { + listeners.length = 0; + } + } + }); + return me; + } + + /** + * Registers a listener for the specified event type(s). + * + * @memberOf Benchmark, Benchmark.Suite + * @param {String} type The event type. + * @param {Function} listener The function to register. + * @returns {Object} The benchmark instance. + * @example + * + * // register a listener for an event type + * bench.on('cycle', listener); + * + * // register a listener for multiple event types + * bench.on('start cycle', listener); + */ + function on(type, listener) { + var me = this, + events = me.events || (me.events = {}); + + forEach(type.split(' '), function(type) { + (hasKey(events, type) + ? events[type] + : (events[type] = []) + ).push(listener); + }); + return me; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Aborts the benchmark without recording times. + * + * @memberOf Benchmark + * @returns {Object} The benchmark instance. + */ + function abort() { + var event, + me = this, + resetting = calledBy.reset; + + if (me.running) { + event = Event('abort'); + me.emit(event); + if (!event.cancelled || resetting) { + // avoid infinite recursion + calledBy.abort = true; + me.reset(); + delete calledBy.abort; + + if (support.timeout) { + clearTimeout(me._timerId); + delete me._timerId; + } + if (!resetting) { + me.aborted = true; + me.running = false; + } + } + } + return me; + } + + /** + * Creates a new benchmark using the same test and options. + * + * @memberOf Benchmark + * @param {Object} options Options object to overwrite cloned options. + * @returns {Object} The new benchmark instance. + * @example + * + * var bizarro = bench.clone({ + * 'name': 'doppelganger' + * }); + */ + function clone(options) { + var me = this, + result = new me.constructor(extend({}, me, options)); + + // correct the `options` object + result.options = extend({}, me.options, options); + + // copy own custom properties + forOwn(me, function(value, key) { + if (!hasKey(result, key)) { + result[key] = deepClone(value); + } + }); + return result; + } + + /** + * Determines if a benchmark is faster than another. + * + * @memberOf Benchmark + * @param {Object} other The benchmark to compare. + * @returns {Number} Returns `-1` if slower, `1` if faster, and `0` if indeterminate. + */ + function compare(other) { + var critical, + zStat, + me = this, + sample1 = me.stats.sample, + sample2 = other.stats.sample, + size1 = sample1.length, + size2 = sample2.length, + maxSize = max(size1, size2), + minSize = min(size1, size2), + u1 = getU(sample1, sample2), + u2 = getU(sample2, sample1), + u = min(u1, u2); + + function getScore(xA, sampleB) { + return reduce(sampleB, function(total, xB) { + return total + (xB > xA ? 0 : xB < xA ? 1 : 0.5); + }, 0); + } + + function getU(sampleA, sampleB) { + return reduce(sampleA, function(total, xA) { + return total + getScore(xA, sampleB); + }, 0); + } + + function getZ(u) { + return (u - ((size1 * size2) / 2)) / sqrt((size1 * size2 * (size1 + size2 + 1)) / 12); + } + + // exit early if comparing the same benchmark + if (me == other) { + return 0; + } + // reject the null hyphothesis the two samples come from the + // same population (i.e. have the same median) if... + if (size1 + size2 > 30) { + // ...the z-stat is greater than 1.96 or less than -1.96 + // http://www.statisticslectures.com/topics/mannwhitneyu/ + zStat = getZ(u); + return abs(zStat) > 1.96 ? (zStat > 0 ? -1 : 1) : 0; + } + // ...the U value is less than or equal the critical U value + // http://www.geoib.com/mann-whitney-u-test.html + critical = maxSize < 5 || minSize < 3 ? 0 : uTable[maxSize][minSize - 3]; + return u <= critical ? (u == u1 ? 1 : -1) : 0; + } + + /** + * Reset properties and abort if running. + * + * @memberOf Benchmark + * @returns {Object} The benchmark instance. + */ + function reset() { + var data, + event, + me = this, + index = 0, + changes = { 'length': 0 }, + queue = { 'length': 0 }; + + if (me.running && !calledBy.abort) { + // no worries, `reset()` is called within `abort()` + calledBy.reset = true; + me.abort(); + delete calledBy.reset; + } + else { + // a non-recursive solution to check if properties have changed + // http://www.jslab.dk/articles/non.recursive.preorder.traversal.part4 + data = { 'destination': me, 'source': extend({}, me.constructor.prototype, me.options) }; + do { + forOwn(data.source, function(value, key) { + var changed, + destination = data.destination, + currValue = destination[key]; + + if (value && typeof value == 'object') { + if (isClassOf(value, 'Array')) { + // check if an array value has changed to a non-array value + if (!isClassOf(currValue, 'Array')) { + changed = currValue = []; + } + // or has changed its length + if (currValue.length != value.length) { + changed = currValue = currValue.slice(0, value.length); + currValue.length = value.length; + } + } + // check if an object has changed to a non-object value + else if (!currValue || typeof currValue != 'object') { + changed = currValue = {}; + } + // register a changed object + if (changed) { + changes[changes.length++] = { 'destination': destination, 'key': key, 'value': currValue }; + } + queue[queue.length++] = { 'destination': currValue, 'source': value }; + } + // register a changed primitive + else if (value !== currValue && !(value == null || isClassOf(value, 'Function'))) { + changes[changes.length++] = { 'destination': destination, 'key': key, 'value': value }; + } + }); + } + while ((data = queue[index++])); + + // if changed emit the `reset` event and if it isn't cancelled reset the benchmark + if (changes.length && (me.emit(event = Event('reset')), !event.cancelled)) { + forEach(changes, function(data) { + data.destination[data.key] = data.value; + }); + } + } + return me; + } + + /** + * Displays relevant benchmark information when coerced to a string. + * + * @name toString + * @memberOf Benchmark + * @returns {String} A string representation of the benchmark instance. + */ + function toStringBench() { + var me = this, + error = me.error, + hz = me.hz, + id = me.id, + stats = me.stats, + size = stats.sample.length, + pm = support.java ? '+/-' : '\xb1', + result = me.name || (isNaN(id) ? id : '<Test #' + id + '>'); + + if (error) { + result += ': ' + join(error); + } else { + result += ' x ' + formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + ' ops/sec ' + pm + + stats.rme.toFixed(2) + '% (' + size + ' run' + (size == 1 ? '' : 's') + ' sampled)'; + } + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Clocks the time taken to execute a test per cycle (secs). + * + * @private + * @param {Object} bench The benchmark instance. + * @returns {Number} The time taken. + */ + function clock() { + var applet, + options = Benchmark.options, + template = { 'begin': 's$=new n$', 'end': 'r$=(new n$-s$)/1e3', 'uid': uid }, + timers = [{ 'ns': timer.ns, 'res': max(0.0015, getRes('ms')), 'unit': 'ms' }]; + + // lazy define for hi-res timers + clock = function(clone) { + var deferred; + if (clone instanceof Deferred) { + deferred = clone; + clone = deferred.benchmark; + } + + var bench = clone._original, + fn = bench.fn, + fnArg = deferred ? getFirstArgument(fn) || 'deferred' : '', + stringable = isStringable(fn); + + var source = { + 'setup': getSource(bench.setup, preprocess('m$.setup()')), + 'fn': getSource(fn, preprocess('m$.fn(' + fnArg + ')')), + 'fnArg': fnArg, + 'teardown': getSource(bench.teardown, preprocess('m$.teardown()')) + }; + + var count = bench.count = clone.count, + decompilable = support.decompilation || stringable, + id = bench.id, + isEmpty = !(source.fn || stringable), + name = bench.name || (typeof id == 'number' ? '<Test #' + id + '>' : id), + ns = timer.ns, + result = 0; + + // init `minTime` if needed + clone.minTime = bench.minTime || (bench.minTime = bench.options.minTime = options.minTime); + + // repair nanosecond timer + // (some Chrome builds erase the `ns` variable after millions of executions) + if (applet) { + try { + ns.nanoTime(); + } catch(e) { + // use non-element to avoid issues with libs that augment them + ns = timer.ns = new applet.Packages.nano; + } + } + + // Compile in setup/teardown functions and the test loop. + // Create a new compiled test, instead of using the cached `bench.compiled`, + // to avoid potential engine optimizations enabled over the life of the test. + var compiled = bench.compiled = createFunction(preprocess('t$'), interpolate( + preprocess(deferred + ? 'var d$=this,#{fnArg}=d$,m$=d$.benchmark._original,f$=m$.fn,su$=m$.setup,td$=m$.teardown;' + + // when `deferred.cycles` is `0` then... + 'if(!d$.cycles){' + + // set `deferred.fn` + 'd$.fn=function(){var #{fnArg}=d$;if(typeof f$=="function"){try{#{fn}\n}catch(e$){f$(d$)}}else{#{fn}\n}};' + + // set `deferred.teardown` + 'd$.teardown=function(){d$.cycles=0;if(typeof td$=="function"){try{#{teardown}\n}catch(e$){td$()}}else{#{teardown}\n}};' + + // execute the benchmark's `setup` + 'if(typeof su$=="function"){try{#{setup}\n}catch(e$){su$()}}else{#{setup}\n};' + + // start timer + 't$.start(d$);' + + // execute `deferred.fn` and return a dummy object + '}d$.fn();return{}' + + : 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count,n$=t$.ns;#{setup}\n#{begin};' + + 'while(i$--){#{fn}\n}#{end};#{teardown}\nreturn{elapsed:r$,uid:"#{uid}"}'), + source + )); + + try { + if (isEmpty) { + // Firefox may remove dead code from Function#toString results + // http://bugzil.la/536085 + throw new Error('The test "' + name + '" is empty. This may be the result of dead code removal.'); + } + else if (!deferred) { + // pretest to determine if compiled code is exits early, usually by a + // rogue `return` statement, by checking for a return object with the uid + bench.count = 1; + compiled = (compiled.call(bench, timer) || {}).uid == uid && compiled; + bench.count = count; + } + } catch(e) { + compiled = null; + clone.error = e || new Error(String(e)); + bench.count = count; + } + // fallback when a test exits early or errors during pretest + if (decompilable && !compiled && !deferred && !isEmpty) { + compiled = createFunction(preprocess('t$'), interpolate( + preprocess( + (clone.error && !stringable + ? 'var r$,s$,m$=this,f$=m$.fn,i$=m$.count' + : 'function f$(){#{fn}\n}var r$,s$,m$=this,i$=m$.count' + ) + + ',n$=t$.ns;#{setup}\n#{begin};m$.f$=f$;while(i$--){m$.f$()}#{end};' + + 'delete m$.f$;#{teardown}\nreturn{elapsed:r$}' + ), + source + )); + + try { + // pretest one more time to check for errors + bench.count = 1; + compiled.call(bench, timer); + bench.compiled = compiled; + bench.count = count; + delete clone.error; + } + catch(e) { + bench.count = count; + if (clone.error) { + compiled = null; + } else { + bench.compiled = compiled; + clone.error = e || new Error(String(e)); + } + } + } + // assign `compiled` to `clone` before calling in case a deferred benchmark + // immediately calls `deferred.resolve()` + clone.compiled = compiled; + // if no errors run the full test loop + if (!clone.error) { + result = compiled.call(deferred || bench, timer).elapsed; + } + return result; + }; + + /*------------------------------------------------------------------------*/ + + /** + * Gets the current timer's minimum resolution (secs). + */ + function getRes(unit) { + var measured, + begin, + count = 30, + divisor = 1e3, + ns = timer.ns, + sample = []; + + // get average smallest measurable time + while (count--) { + if (unit == 'us') { + divisor = 1e6; + if (ns.stop) { + ns.start(); + while (!(measured = ns.microseconds())) { } + } else if (ns[perfName]) { + divisor = 1e3; + measured = Function('n', 'var r,s=n.' + perfName + '();while(!(r=n.' + perfName + '()-s)){};return r')(ns); + } else { + begin = ns(); + while (!(measured = ns() - begin)) { } + } + } + else if (unit == 'ns') { + divisor = 1e9; + if (ns.nanoTime) { + begin = ns.nanoTime(); + while (!(measured = ns.nanoTime() - begin)) { } + } else { + begin = (begin = ns())[0] + (begin[1] / divisor); + while (!(measured = ((measured = ns())[0] + (measured[1] / divisor)) - begin)) { } + divisor = 1; + } + } + else { + begin = new ns; + while (!(measured = new ns - begin)) { } + } + // check for broken timers (nanoTime may have issues) + // http://alivebutsleepy.srnet.cz/unreliable-system-nanotime/ + if (measured > 0) { + sample.push(measured); + } else { + sample.push(Infinity); + break; + } + } + // convert to seconds + return getMean(sample) / divisor; + } + + /** + * Replaces all occurrences of `$` with a unique number and + * template tokens with content. + */ + function preprocess(code) { + return interpolate(code, template).replace(/\$/g, /\d+/.exec(uid)); + } + + /*------------------------------------------------------------------------*/ + + // detect nanosecond support from a Java applet + each(doc && doc.applets || [], function(element) { + return !(timer.ns = applet = 'nanoTime' in element && element); + }); + + // check type in case Safari returns an object instead of a number + try { + if (typeof timer.ns.nanoTime() == 'number') { + timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); + } + } catch(e) { } + + // detect Chrome's microsecond timer: + // enable benchmarking via the --enable-benchmarking command + // line switch in at least Chrome 7 to use chrome.Interval + try { + if ((timer.ns = new (window.chrome || window.chromium).Interval)) { + timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); + } + } catch(e) { } + + // detect `performance.now` microsecond resolution timer + if ((timer.ns = perfName && perfObject)) { + timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); + } + + // detect Node's nanosecond resolution timer available in Node >= 0.8 + if (processObject && typeof (timer.ns = processObject.hrtime) == 'function') { + timers.push({ 'ns': timer.ns, 'res': getRes('ns'), 'unit': 'ns' }); + } + + // detect Wade Simmons' Node microtime module + if (microtimeObject && typeof (timer.ns = microtimeObject.now) == 'function') { + timers.push({ 'ns': timer.ns, 'res': getRes('us'), 'unit': 'us' }); + } + + // pick timer with highest resolution + timer = reduce(timers, function(timer, other) { + return other.res < timer.res ? other : timer; + }); + + // remove unused applet + if (timer.unit != 'ns' && applet) { + applet = destroyElement(applet); + } + // error if there are no working timers + if (timer.res == Infinity) { + throw new Error('Benchmark.js was unable to find a working timer.'); + } + // use API of chosen timer + if (timer.unit == 'ns') { + if (timer.ns.nanoTime) { + extend(template, { + 'begin': 's$=n$.nanoTime()', + 'end': 'r$=(n$.nanoTime()-s$)/1e9' + }); + } else { + extend(template, { + 'begin': 's$=n$()', + 'end': 'r$=n$(s$);r$=r$[0]+(r$[1]/1e9)' + }); + } + } + else if (timer.unit == 'us') { + if (timer.ns.stop) { + extend(template, { + 'begin': 's$=n$.start()', + 'end': 'r$=n$.microseconds()/1e6' + }); + } else if (perfName) { + extend(template, { + 'begin': 's$=n$.' + perfName + '()', + 'end': 'r$=(n$.' + perfName + '()-s$)/1e3' + }); + } else { + extend(template, { + 'begin': 's$=n$()', + 'end': 'r$=(n$()-s$)/1e6' + }); + } + } + + // define `timer` methods + timer.start = createFunction(preprocess('o$'), + preprocess('var n$=this.ns,#{begin};o$.elapsed=0;o$.timeStamp=s$')); + + timer.stop = createFunction(preprocess('o$'), + preprocess('var n$=this.ns,s$=o$.timeStamp,#{end};o$.elapsed=r$')); + + // resolve time span required to achieve a percent uncertainty of at most 1% + // http://spiff.rit.edu/classes/phys273/uncert/uncert.html + options.minTime || (options.minTime = max(timer.res / 2 / 0.01, 0.05)); + return clock.apply(null, arguments); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Computes stats on benchmark results. + * + * @private + * @param {Object} bench The benchmark instance. + * @param {Object} options The options object. + */ + function compute(bench, options) { + options || (options = {}); + + var async = options.async, + elapsed = 0, + initCount = bench.initCount, + minSamples = bench.minSamples, + queue = [], + sample = bench.stats.sample; + + /** + * Adds a clone to the queue. + */ + function enqueue() { + queue.push(bench.clone({ + '_original': bench, + 'events': { + 'abort': [update], + 'cycle': [update], + 'error': [update], + 'start': [update] + } + })); + } + + /** + * Updates the clone/original benchmarks to keep their data in sync. + */ + function update(event) { + var clone = this, + type = event.type; + + if (bench.running) { + if (type == 'start') { + // Note: `clone.minTime` prop is inited in `clock()` + clone.count = bench.initCount; + } + else { + if (type == 'error') { + bench.error = clone.error; + } + if (type == 'abort') { + bench.abort(); + bench.emit('cycle'); + } else { + event.currentTarget = event.target = bench; + bench.emit(event); + } + } + } else if (bench.aborted) { + // clear abort listeners to avoid triggering bench's abort/cycle again + clone.events.abort.length = 0; + clone.abort(); + } + } + + /** + * Determines if more clones should be queued or if cycling should stop. + */ + function evaluate(event) { + var critical, + df, + mean, + moe, + rme, + sd, + sem, + variance, + clone = event.target, + done = bench.aborted, + now = +new Date, + size = sample.push(clone.times.period), + maxedOut = size >= minSamples && (elapsed += now - clone.times.timeStamp) / 1e3 > bench.maxTime, + times = bench.times, + varOf = function(sum, x) { return sum + pow(x - mean, 2); }; + + // exit early for aborted or unclockable tests + if (done || clone.hz == Infinity) { + maxedOut = !(size = sample.length = queue.length = 0); + } + + if (!done) { + // sample mean (estimate of the population mean) + mean = getMean(sample); + // sample variance (estimate of the population variance) + variance = reduce(sample, varOf, 0) / (size - 1) || 0; + // sample standard deviation (estimate of the population standard deviation) + sd = sqrt(variance); + // standard error of the mean (a.k.a. the standard deviation of the sampling distribution of the sample mean) + sem = sd / sqrt(size); + // degrees of freedom + df = size - 1; + // critical value + critical = tTable[Math.round(df) || 1] || tTable.infinity; + // margin of error + moe = sem * critical; + // relative margin of error + rme = (moe / mean) * 100 || 0; + + extend(bench.stats, { + 'deviation': sd, + 'mean': mean, + 'moe': moe, + 'rme': rme, + 'sem': sem, + 'variance': variance + }); + + // Abort the cycle loop when the minimum sample size has been collected + // and the elapsed time exceeds the maximum time allowed per benchmark. + // We don't count cycle delays toward the max time because delays may be + // increased by browsers that clamp timeouts for inactive tabs. + // https://developer.mozilla.org/en/window.setTimeout#Inactive_tabs + if (maxedOut) { + // reset the `initCount` in case the benchmark is rerun + bench.initCount = initCount; + bench.running = false; + done = true; + times.elapsed = (now - times.timeStamp) / 1e3; + } + if (bench.hz != Infinity) { + bench.hz = 1 / mean; + times.cycle = mean * bench.count; + times.period = mean; + } + } + // if time permits, increase sample size to reduce the margin of error + if (queue.length < 2 && !maxedOut) { + enqueue(); + } + // abort the invoke cycle when done + event.aborted = done; + } + + // init queue and begin + enqueue(); + invoke(queue, { + 'name': 'run', + 'args': { 'async': async }, + 'queued': true, + 'onCycle': evaluate, + 'onComplete': function() { bench.emit('complete'); } + }); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Cycles a benchmark until a run `count` can be established. + * + * @private + * @param {Object} clone The cloned benchmark instance. + * @param {Object} options The options object. + */ + function cycle(clone, options) { + options || (options = {}); + + var deferred; + if (clone instanceof Deferred) { + deferred = clone; + clone = clone.benchmark; + } + + var clocked, + cycles, + divisor, + event, + minTime, + period, + async = options.async, + bench = clone._original, + count = clone.count, + times = clone.times; + + // continue, if not aborted between cycles + if (clone.running) { + // `minTime` is set to `Benchmark.options.minTime` in `clock()` + cycles = ++clone.cycles; + clocked = deferred ? deferred.elapsed : clock(clone); + minTime = clone.minTime; + + if (cycles > bench.cycles) { + bench.cycles = cycles; + } + if (clone.error) { + event = Event('error'); + event.message = clone.error; + clone.emit(event); + if (!event.cancelled) { + clone.abort(); + } + } + } + + // continue, if not errored + if (clone.running) { + // time taken to complete last test cycle + bench.times.cycle = times.cycle = clocked; + // seconds per operation + period = bench.times.period = times.period = clocked / count; + // ops per second + bench.hz = clone.hz = 1 / period; + // avoid working our way up to this next time + bench.initCount = clone.initCount = count; + // do we need to do another cycle? + clone.running = clocked < minTime; + + if (clone.running) { + // tests may clock at `0` when `initCount` is a small number, + // to avoid that we set its count to something a bit higher + if (!clocked && (divisor = divisors[clone.cycles]) != null) { + count = floor(4e6 / divisor); + } + // calculate how many more iterations it will take to achive the `minTime` + if (count <= clone.count) { + count += Math.ceil((minTime - clocked) / period); + } + clone.running = count != Infinity; + } + } + // should we exit early? + event = Event('cycle'); + clone.emit(event); + if (event.aborted) { + clone.abort(); + } + // figure out what to do next + if (clone.running) { + // start a new cycle + clone.count = count; + if (deferred) { + clone.compiled.call(deferred, timer); + } else if (async) { + delay(clone, function() { cycle(clone, options); }); + } else { + cycle(clone); + } + } + else { + // fix TraceMonkey bug associated with clock fallbacks + // http://bugzil.la/509069 + if (support.browser) { + runScript(uid + '=1;delete ' + uid); + } + // done + clone.emit('complete'); + } + } + + /*--------------------------------------------------------------------------*/ + + /** + * Runs the benchmark. + * + * @memberOf Benchmark + * @param {Object} [options={}] Options object. + * @returns {Object} The benchmark instance. + * @example + * + * // basic usage + * bench.run(); + * + * // or with options + * bench.run({ 'async': true }); + */ + function run(options) { + var me = this, + event = Event('start'); + + // set `running` to `false` so `reset()` won't call `abort()` + me.running = false; + me.reset(); + me.running = true; + + me.count = me.initCount; + me.times.timeStamp = +new Date; + me.emit(event); + + if (!event.cancelled) { + options = { 'async': ((options = options && options.async) == null ? me.async : options) && support.timeout }; + + // for clones created within `compute()` + if (me._original) { + if (me.defer) { + Deferred(me); + } else { + cycle(me, options); + } + } + // for original benchmarks + else { + compute(me, options); + } + } + return me; + } + + /*--------------------------------------------------------------------------*/ + + // Firefox 1 erroneously defines variable and argument names of functions on + // the function itself as non-configurable properties with `undefined` values. + // The bugginess continues as the `Benchmark` constructor has an argument + // named `options` and Firefox 1 will not assign a value to `Benchmark.options`, + // making it non-writable in the process, unless it is the first property + // assigned by for-in loop of `extend()`. + extend(Benchmark, { + + /** + * The default options copied by benchmark instances. + * + * @static + * @memberOf Benchmark + * @type Object + */ + 'options': { + + /** + * A flag to indicate that benchmark cycles will execute asynchronously + * by default. + * + * @memberOf Benchmark.options + * @type Boolean + */ + 'async': false, + + /** + * A flag to indicate that the benchmark clock is deferred. + * + * @memberOf Benchmark.options + * @type Boolean + */ + 'defer': false, + + /** + * The delay between test cycles (secs). + * @memberOf Benchmark.options + * @type Number + */ + 'delay': 0.005, + + /** + * Displayed by Benchmark#toString when a `name` is not available + * (auto-generated if absent). + * + * @memberOf Benchmark.options + * @type String + */ + 'id': undefined, + + /** + * The default number of times to execute a test on a benchmark's first cycle. + * + * @memberOf Benchmark.options + * @type Number + */ + 'initCount': 1, + + /** + * The maximum time a benchmark is allowed to run before finishing (secs). + * + * Note: Cycle delays aren't counted toward the maximum time. + * + * @memberOf Benchmark.options + * @type Number + */ + 'maxTime': 5, + + /** + * The minimum sample size required to perform statistical analysis. + * + * @memberOf Benchmark.options + * @type Number + */ + 'minSamples': 5, + + /** + * The time needed to reduce the percent uncertainty of measurement to 1% (secs). + * + * @memberOf Benchmark.options + * @type Number + */ + 'minTime': 0, + + /** + * The name of the benchmark. + * + * @memberOf Benchmark.options + * @type String + */ + 'name': undefined, + + /** + * An event listener called when the benchmark is aborted. + * + * @memberOf Benchmark.options + * @type Function + */ + 'onAbort': undefined, + + /** + * An event listener called when the benchmark completes running. + * + * @memberOf Benchmark.options + * @type Function + */ + 'onComplete': undefined, + + /** + * An event listener called after each run cycle. + * + * @memberOf Benchmark.options + * @type Function + */ + 'onCycle': undefined, + + /** + * An event listener called when a test errors. + * + * @memberOf Benchmark.options + * @type Function + */ + 'onError': undefined, + + /** + * An event listener called when the benchmark is reset. + * + * @memberOf Benchmark.options + * @type Function + */ + 'onReset': undefined, + + /** + * An event listener called when the benchmark starts running. + * + * @memberOf Benchmark.options + * @type Function + */ + 'onStart': undefined + }, + + /** + * Platform object with properties describing things like browser name, + * version, and operating system. + * + * @static + * @memberOf Benchmark + * @type Object + */ + 'platform': req('platform') || window.platform || { + + /** + * The platform description. + * + * @memberOf Benchmark.platform + * @type String + */ + 'description': window.navigator && navigator.userAgent || null, + + /** + * The name of the browser layout engine. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'layout': null, + + /** + * The name of the product hosting the browser. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'product': null, + + /** + * The name of the browser/environment. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'name': null, + + /** + * The name of the product's manufacturer. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'manufacturer': null, + + /** + * The name of the operating system. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'os': null, + + /** + * The alpha/beta release indicator. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'prerelease': null, + + /** + * The browser/environment version. + * + * @memberOf Benchmark.platform + * @type String|Null + */ + 'version': null, + + /** + * Return platform description when the platform object is coerced to a string. + * + * @memberOf Benchmark.platform + * @type Function + * @returns {String} The platform description. + */ + 'toString': function() { + return this.description || ''; + } + }, + + /** + * The semantic version number. + * + * @static + * @memberOf Benchmark + * @type String + */ + 'version': '1.0.0', + + // an object of environment/feature detection flags + 'support': support, + + // clone objects + 'deepClone': deepClone, + + // iteration utility + 'each': each, + + // augment objects + 'extend': extend, + + // generic Array#filter + 'filter': filter, + + // generic Array#forEach + 'forEach': forEach, + + // generic own property iteration utility + 'forOwn': forOwn, + + // converts a number to a comma-separated string + 'formatNumber': formatNumber, + + // generic Object#hasOwnProperty + // (trigger hasKey's lazy define before assigning it to Benchmark) + 'hasKey': (hasKey(Benchmark, ''), hasKey), + + // generic Array#indexOf + 'indexOf': indexOf, + + // template utility + 'interpolate': interpolate, + + // invokes a method on each item in an array + 'invoke': invoke, + + // generic Array#join for arrays and objects + 'join': join, + + // generic Array#map + 'map': map, + + // retrieves a property value from each item in an array + 'pluck': pluck, + + // generic Array#reduce + 'reduce': reduce + }); + + /*--------------------------------------------------------------------------*/ + + extend(Benchmark.prototype, { + + /** + * The number of times a test was executed. + * + * @memberOf Benchmark + * @type Number + */ + 'count': 0, + + /** + * The number of cycles performed while benchmarking. + * + * @memberOf Benchmark + * @type Number + */ + 'cycles': 0, + + /** + * The number of executions per second. + * + * @memberOf Benchmark + * @type Number + */ + 'hz': 0, + + /** + * The compiled test function. + * + * @memberOf Benchmark + * @type Function|String + */ + 'compiled': undefined, + + /** + * The error object if the test failed. + * + * @memberOf Benchmark + * @type Object + */ + 'error': undefined, + + /** + * The test to benchmark. + * + * @memberOf Benchmark + * @type Function|String + */ + 'fn': undefined, + + /** + * A flag to indicate if the benchmark is aborted. + * + * @memberOf Benchmark + * @type Boolean + */ + 'aborted': false, + + /** + * A flag to indicate if the benchmark is running. + * + * @memberOf Benchmark + * @type Boolean + */ + 'running': false, + + /** + * Compiled into the test and executed immediately **before** the test loop. + * + * @memberOf Benchmark + * @type Function|String + * @example + * + * // basic usage + * var bench = Benchmark({ + * 'setup': function() { + * var c = this.count, + * element = document.getElementById('container'); + * while (c--) { + * element.appendChild(document.createElement('div')); + * } + * }, + * 'fn': function() { + * element.removeChild(element.lastChild); + * } + * }); + * + * // compiles to something like: + * var c = this.count, + * element = document.getElementById('container'); + * while (c--) { + * element.appendChild(document.createElement('div')); + * } + * var start = new Date; + * while (count--) { + * element.removeChild(element.lastChild); + * } + * var end = new Date - start; + * + * // or using strings + * var bench = Benchmark({ + * 'setup': '\ + * var a = 0;\n\ + * (function() {\n\ + * (function() {\n\ + * (function() {', + * 'fn': 'a += 1;', + * 'teardown': '\ + * }())\n\ + * }())\n\ + * }())' + * }); + * + * // compiles to something like: + * var a = 0; + * (function() { + * (function() { + * (function() { + * var start = new Date; + * while (count--) { + * a += 1; + * } + * var end = new Date - start; + * }()) + * }()) + * }()) + */ + 'setup': noop, + + /** + * Compiled into the test and executed immediately **after** the test loop. + * + * @memberOf Benchmark + * @type Function|String + */ + 'teardown': noop, + + /** + * An object of stats including mean, margin or error, and standard deviation. + * + * @memberOf Benchmark + * @type Object + */ + 'stats': { + + /** + * The margin of error. + * + * @memberOf Benchmark#stats + * @type Number + */ + 'moe': 0, + + /** + * The relative margin of error (expressed as a percentage of the mean). + * + * @memberOf Benchmark#stats + * @type Number + */ + 'rme': 0, + + /** + * The standard error of the mean. + * + * @memberOf Benchmark#stats + * @type Number + */ + 'sem': 0, + + /** + * The sample standard deviation. + * + * @memberOf Benchmark#stats + * @type Number + */ + 'deviation': 0, + + /** + * The sample arithmetic mean. + * + * @memberOf Benchmark#stats + * @type Number + */ + 'mean': 0, + + /** + * The array of sampled periods. + * + * @memberOf Benchmark#stats + * @type Array + */ + 'sample': [], + + /** + * The sample variance. + * + * @memberOf Benchmark#stats + * @type Number + */ + 'variance': 0 + }, + + /** + * An object of timing data including cycle, elapsed, period, start, and stop. + * + * @memberOf Benchmark + * @type Object + */ + 'times': { + + /** + * The time taken to complete the last cycle (secs). + * + * @memberOf Benchmark#times + * @type Number + */ + 'cycle': 0, + + /** + * The time taken to complete the benchmark (secs). + * + * @memberOf Benchmark#times + * @type Number + */ + 'elapsed': 0, + + /** + * The time taken to execute the test once (secs). + * + * @memberOf Benchmark#times + * @type Number + */ + 'period': 0, + + /** + * A timestamp of when the benchmark started (ms). + * + * @memberOf Benchmark#times + * @type Number + */ + 'timeStamp': 0 + }, + + // aborts benchmark (does not record times) + 'abort': abort, + + // creates a new benchmark using the same test and options + 'clone': clone, + + // compares benchmark's hertz with another + 'compare': compare, + + // executes listeners + 'emit': emit, + + // get listeners + 'listeners': listeners, + + // unregister listeners + 'off': off, + + // register listeners + 'on': on, + + // reset benchmark properties + 'reset': reset, + + // runs the benchmark + 'run': run, + + // pretty print benchmark info + 'toString': toStringBench + }); + + /*--------------------------------------------------------------------------*/ + + extend(Deferred.prototype, { + + /** + * The deferred benchmark instance. + * + * @memberOf Benchmark.Deferred + * @type Object + */ + 'benchmark': null, + + /** + * The number of deferred cycles performed while benchmarking. + * + * @memberOf Benchmark.Deferred + * @type Number + */ + 'cycles': 0, + + /** + * The time taken to complete the deferred benchmark (secs). + * + * @memberOf Benchmark.Deferred + * @type Number + */ + 'elapsed': 0, + + /** + * A timestamp of when the deferred benchmark started (ms). + * + * @memberOf Benchmark.Deferred + * @type Number + */ + 'timeStamp': 0, + + // cycles/completes the deferred benchmark + 'resolve': resolve + }); + + /*--------------------------------------------------------------------------*/ + + extend(Event.prototype, { + + /** + * A flag to indicate if the emitters listener iteration is aborted. + * + * @memberOf Benchmark.Event + * @type Boolean + */ + 'aborted': false, + + /** + * A flag to indicate if the default action is cancelled. + * + * @memberOf Benchmark.Event + * @type Boolean + */ + 'cancelled': false, + + /** + * The object whose listeners are currently being processed. + * + * @memberOf Benchmark.Event + * @type Object + */ + 'currentTarget': undefined, + + /** + * The return value of the last executed listener. + * + * @memberOf Benchmark.Event + * @type Mixed + */ + 'result': undefined, + + /** + * The object to which the event was originally emitted. + * + * @memberOf Benchmark.Event + * @type Object + */ + 'target': undefined, + + /** + * A timestamp of when the event was created (ms). + * + * @memberOf Benchmark.Event + * @type Number + */ + 'timeStamp': 0, + + /** + * The event type. + * + * @memberOf Benchmark.Event + * @type String + */ + 'type': '' + }); + + /*--------------------------------------------------------------------------*/ + + /** + * The default options copied by suite instances. + * + * @static + * @memberOf Benchmark.Suite + * @type Object + */ + Suite.options = { + + /** + * The name of the suite. + * + * @memberOf Benchmark.Suite.options + * @type String + */ + 'name': undefined + }; + + /*--------------------------------------------------------------------------*/ + + extend(Suite.prototype, { + + /** + * The number of benchmarks in the suite. + * + * @memberOf Benchmark.Suite + * @type Number + */ + 'length': 0, + + /** + * A flag to indicate if the suite is aborted. + * + * @memberOf Benchmark.Suite + * @type Boolean + */ + 'aborted': false, + + /** + * A flag to indicate if the suite is running. + * + * @memberOf Benchmark.Suite + * @type Boolean + */ + 'running': false, + + /** + * An `Array#forEach` like method. + * Callbacks may terminate the loop by explicitly returning `false`. + * + * @memberOf Benchmark.Suite + * @param {Function} callback The function called per iteration. + * @returns {Object} The suite iterated over. + */ + 'forEach': methodize(forEach), + + /** + * An `Array#indexOf` like method. + * + * @memberOf Benchmark.Suite + * @param {Mixed} value The value to search for. + * @returns {Number} The index of the matched value or `-1`. + */ + 'indexOf': methodize(indexOf), + + /** + * Invokes a method on all benchmarks in the suite. + * + * @memberOf Benchmark.Suite + * @param {String|Object} name The name of the method to invoke OR options object. + * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. + * @returns {Array} A new array of values returned from each method invoked. + */ + 'invoke': methodize(invoke), + + /** + * Converts the suite of benchmarks to a string. + * + * @memberOf Benchmark.Suite + * @param {String} [separator=','] A string to separate each element of the array. + * @returns {String} The string. + */ + 'join': [].join, + + /** + * An `Array#map` like method. + * + * @memberOf Benchmark.Suite + * @param {Function} callback The function called per iteration. + * @returns {Array} A new array of values returned by the callback. + */ + 'map': methodize(map), + + /** + * Retrieves the value of a specified property from all benchmarks in the suite. + * + * @memberOf Benchmark.Suite + * @param {String} property The property to pluck. + * @returns {Array} A new array of property values. + */ + 'pluck': methodize(pluck), + + /** + * Removes the last benchmark from the suite and returns it. + * + * @memberOf Benchmark.Suite + * @returns {Mixed} The removed benchmark. + */ + 'pop': [].pop, + + /** + * Appends benchmarks to the suite. + * + * @memberOf Benchmark.Suite + * @returns {Number} The suite's new length. + */ + 'push': [].push, + + /** + * Sorts the benchmarks of the suite. + * + * @memberOf Benchmark.Suite + * @param {Function} [compareFn=null] A function that defines the sort order. + * @returns {Object} The sorted suite. + */ + 'sort': [].sort, + + /** + * An `Array#reduce` like method. + * + * @memberOf Benchmark.Suite + * @param {Function} callback The function called per iteration. + * @param {Mixed} accumulator Initial value of the accumulator. + * @returns {Mixed} The accumulator. + */ + 'reduce': methodize(reduce), + + // aborts all benchmarks in the suite + 'abort': abortSuite, + + // adds a benchmark to the suite + 'add': add, + + // creates a new suite with cloned benchmarks + 'clone': cloneSuite, + + // executes listeners of a specified type + 'emit': emit, + + // creates a new suite of filtered benchmarks + 'filter': filterSuite, + + // get listeners + 'listeners': listeners, + + // unregister listeners + 'off': off, + + // register listeners + 'on': on, + + // resets all benchmarks in the suite + 'reset': resetSuite, + + // runs all benchmarks in the suite + 'run': runSuite, + + // array methods + 'concat': concat, + + 'reverse': reverse, + + 'shift': shift, + + 'slice': slice, + + 'splice': splice, + + 'unshift': unshift + }); + + /*--------------------------------------------------------------------------*/ + + // expose Deferred, Event and Suite + extend(Benchmark, { + 'Deferred': Deferred, + 'Event': Event, + 'Suite': Suite + }); + + // expose Benchmark + // some AMD build optimizers, like r.js, check for specific condition patterns like the following: + if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { + // define as an anonymous module so, through path mapping, it can be aliased + define(function() { + return Benchmark; + }); + } + // check for `exports` after `define` in case a build optimizer adds an `exports` object + else if (freeExports) { + // in Node.js or RingoJS v0.8.0+ + if (typeof module == 'object' && module && module.exports == freeExports) { + (module.exports = Benchmark).Benchmark = Benchmark; + } + // in Narwhal or RingoJS v0.7.0- + else { + freeExports.Benchmark = Benchmark; + } + } + // in a browser or Rhino + else { + // use square bracket notation so Closure Compiler won't munge `Benchmark` + // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export + window['Benchmark'] = Benchmark; + } + + // trigger clock's lazy define early to avoid a security error + if (support.air) { + clock({ '_original': { 'fn': noop, 'count': 1, 'options': {} } }); + } +}(this)); diff --git a/web/src/vendor/benchmark/doc/README.md b/web/src/vendor/benchmark/doc/README.md new file mode 100644 index 00000000..5ac99e37 --- /dev/null +++ b/web/src/vendor/benchmark/doc/README.md @@ -0,0 +1,2629 @@ +# Benchmark.js <sup>v1.0.0</sup> + +<!-- div --> + + +<!-- div --> + +## <a id="Benchmark"></a>`Benchmark` +* [`Benchmark`](#benchmarkname-fn--options) +* [`Benchmark.version`](#benchmarkversion) +* [`Benchmark.deepClone`](#benchmarkdeepclonevalue) +* [`Benchmark.each`](#benchmarkeachobject-callback-thisarg) +* [`Benchmark.extend`](#benchmarkextenddestination--source) +* [`Benchmark.filter`](#benchmarkfilterarray-callback-thisarg) +* [`Benchmark.forEach`](#benchmarkforeacharray-callback-thisarg) +* [`Benchmark.formatNumber`](#benchmarkformatnumbernumber) +* [`Benchmark.forOwn`](#benchmarkforownobject-callback-thisarg) +* [`Benchmark.hasKey`](#benchmarkhaskeyobject-key) +* [`Benchmark.indexOf`](#benchmarkindexofarray-value--fromindex0) +* [`Benchmark.interpolate`](#benchmarkinterpolatestring-object) +* [`Benchmark.invoke`](#benchmarkinvokebenches-name--arg1-arg2-) +* [`Benchmark.join`](#benchmarkjoinobject--separator1--separator2:) +* [`Benchmark.map`](#benchmarkmaparray-callback-thisarg) +* [`Benchmark.pluck`](#benchmarkpluckarray-property) +* [`Benchmark.reduce`](#benchmarkreducearray-callback-accumulator) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype` +* [`Benchmark.prototype.aborted`](#benchmarkprototypeaborted) +* [`Benchmark.prototype.compiled`](#benchmarkprototypecompiled) +* [`Benchmark.prototype.count`](#benchmarkprototypecount) +* [`Benchmark.prototype.cycles`](#benchmarkprototypecycles) +* [`Benchmark.prototype.fn`](#benchmarkprototypefn) +* [`Benchmark.prototype.hz`](#benchmarkprototypehz) +* [`Benchmark.prototype.running`](#benchmarkprototyperunning) +* [`Benchmark.prototype.setup`](#benchmarkprototypesetup) +* [`Benchmark.prototype.teardown`](#benchmarkprototypeteardown) +* [`Benchmark.prototype.abort`](#benchmarkprototypeabort) +* [`Benchmark.prototype.clone`](#benchmarkprototypecloneoptions) +* [`Benchmark.prototype.compare`](#benchmarkprototypecompareother) +* [`Benchmark.prototype.emit`](#benchmarkprototypeemittype) +* [`Benchmark.prototype.listeners`](#benchmarkprototypelistenerstype) +* [`Benchmark.prototype.off`](#benchmarkprototypeofftype-listener) +* [`Benchmark.prototype.on`](#benchmarkprototypeontype-listener) +* [`Benchmark.prototype.reset`](#benchmarkprototypereset) +* [`Benchmark.prototype.run`](#benchmarkprototyperunoptions) +* [`Benchmark.prototype.toString`](#benchmarkprototypetostring) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.options` +* [`Benchmark.options`](#benchmarkoptions) +* [`Benchmark.options.async`](#benchmarkoptionsasync) +* [`Benchmark.options.defer`](#benchmarkoptionsdefer) +* [`Benchmark.options.delay`](#benchmarkoptionsdelay) +* [`Benchmark.options.id`](#benchmarkoptionsid) +* [`Benchmark.options.initCount`](#benchmarkoptionsinitcount) +* [`Benchmark.options.maxTime`](#benchmarkoptionsmaxtime) +* [`Benchmark.options.minSamples`](#benchmarkoptionsminsamples) +* [`Benchmark.options.minTime`](#benchmarkoptionsmintime) +* [`Benchmark.options.name`](#benchmarkoptionsname) +* [`Benchmark.options.onAbort`](#benchmarkoptionsonabort) +* [`Benchmark.options.onComplete`](#benchmarkoptionsoncomplete) +* [`Benchmark.options.onCycle`](#benchmarkoptionsoncycle) +* [`Benchmark.options.onError`](#benchmarkoptionsonerror) +* [`Benchmark.options.onReset`](#benchmarkoptionsonreset) +* [`Benchmark.options.onStart`](#benchmarkoptionsonstart) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.platform` +* [`Benchmark.platform`](#benchmarkplatform) +* [`Benchmark.platform.description`](#benchmarkplatformdescription) +* [`Benchmark.platform.layout`](#benchmarkplatformlayout) +* [`Benchmark.platform.manufacturer`](#benchmarkplatformmanufacturer) +* [`Benchmark.platform.name`](#benchmarkplatformname) +* [`Benchmark.platform.os`](#benchmarkplatformos) +* [`Benchmark.platform.prerelease`](#benchmarkplatformprerelease) +* [`Benchmark.platform.product`](#benchmarkplatformproduct) +* [`Benchmark.platform.version`](#benchmarkplatformversion) +* [`Benchmark.platform.toString`](#benchmarkplatformtostring) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.support` +* [`Benchmark.support`](#benchmarksupport) +* [`Benchmark.support.air`](#benchmarksupportair) +* [`Benchmark.support.argumentsClass`](#benchmarksupportargumentsclass) +* [`Benchmark.support.browser`](#benchmarksupportbrowser) +* [`Benchmark.support.charByIndex`](#benchmarksupportcharbyindex) +* [`Benchmark.support.charByOwnIndex`](#benchmarksupportcharbyownindex) +* [`Benchmark.support.decompilation`](#benchmarksupportdecompilation) +* [`Benchmark.support.descriptors`](#benchmarksupportdescriptors) +* [`Benchmark.support.getAllKeys`](#benchmarksupportgetallkeys) +* [`Benchmark.support.iteratesOwnLast`](#benchmarksupportiteratesownfirst) +* [`Benchmark.support.java`](#benchmarksupportjava) +* [`Benchmark.support.nodeClass`](#benchmarksupportnodeclass) +* [`Benchmark.support.timeout`](#benchmarksupporttimeout) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype.error` +* [`Benchmark.prototype.error`](#benchmarkprototypeerror) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype.stats` +* [`Benchmark.prototype.stats`](#benchmarkprototypestats) +* [`Benchmark.prototype.stats.deviation`](#benchmark-statsdeviation) +* [`Benchmark.prototype.stats.mean`](#benchmark-statsmean) +* [`Benchmark.prototype.stats.moe`](#benchmark-statsmoe) +* [`Benchmark.prototype.stats.rme`](#benchmark-statsrme) +* [`Benchmark.prototype.stats.sample`](#benchmark-statssample) +* [`Benchmark.prototype.stats.sem`](#benchmark-statssem) +* [`Benchmark.prototype.stats.variance`](#benchmark-statsvariance) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype.times` +* [`Benchmark.prototype.times`](#benchmarkprototypetimes) +* [`Benchmark.prototype.times.cycle`](#benchmark-timescycle) +* [`Benchmark.prototype.times.elapsed`](#benchmark-timeselapsed) +* [`Benchmark.prototype.times.period`](#benchmark-timesperiod) +* [`Benchmark.prototype.times.timeStamp`](#benchmark-timestimestamp) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Deferred` +* [`Benchmark.Deferred`](#benchmarkdeferredclone) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Deferred.prototype` +* [`Benchmark.Deferred.prototype.benchmark`](#benchmarkdeferredprototypebenchmark) +* [`Benchmark.Deferred.prototype.cycles`](#benchmarkdeferredprototypecycles) +* [`Benchmark.Deferred.prototype.elapsed`](#benchmarkdeferredprototypeelapsed) +* [`Benchmark.Deferred.prototype.resolve`](#benchmarkdeferredprototyperesolve) +* [`Benchmark.Deferred.prototype.timeStamp`](#benchmarkdeferredprototypetimestamp) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event` +* [`Benchmark.Event`](#benchmarkeventtype) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event.prototype` +* [`Benchmark.Event.prototype.aborted`](#benchmarkeventprototypeaborted) +* [`Benchmark.Event.prototype.cancelled`](#benchmarkeventprototypecancelled) +* [`Benchmark.Event.prototype.result`](#benchmarkeventprototyperesult) +* [`Benchmark.Event.prototype.timeStamp`](#benchmarkeventprototypetimestamp) +* [`Benchmark.Event.prototype.type`](#benchmarkeventprototypetype) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event.prototype.currentTarget` +* [`Benchmark.Event.prototype.currentTarget`](#benchmarkeventprototypecurrenttarget) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event.prototype.target` +* [`Benchmark.Event.prototype.target`](#benchmarkeventprototypetarget) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Suite` +* [`Benchmark.Suite`](#benchmarksuitename--options) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Suite.prototype` +* [`Benchmark.Suite.prototype.aborted`](#benchmarksuiteprototypeaborted) +* [`Benchmark.Suite.prototype.length`](#benchmarksuiteprototypelength) +* [`Benchmark.Suite.prototype.running`](#benchmarksuiteprototyperunning) +* [`Benchmark.Suite.prototype.abort`](#benchmarksuiteprototypeabort) +* [`Benchmark.Suite.prototype.add`](#benchmarksuiteprototypeaddname-fn--options) +* [`Benchmark.Suite.prototype.clone`](#benchmarksuiteprototypecloneoptions) +* [`Benchmark.Suite.prototype.emit`](#benchmarkprototypeemittype) +* [`Benchmark.Suite.prototype.filter`](#benchmarksuiteprototypefiltercallback) +* [`Benchmark.Suite.prototype.forEach`](#benchmarksuiteprototypeforeachcallback) +* [`Benchmark.Suite.prototype.indexOf`](#benchmarksuiteprototypeindexofvalue) +* [`Benchmark.Suite.prototype.invoke`](#benchmarksuiteprototypeinvokename--arg1-arg2-) +* [`Benchmark.Suite.prototype.join`](#benchmarksuiteprototypejoinseparator-) +* [`Benchmark.Suite.prototype.listeners`](#benchmarkprototypelistenerstype) +* [`Benchmark.Suite.prototype.map`](#benchmarksuiteprototypemapcallback) +* [`Benchmark.Suite.prototype.off`](#benchmarkprototypeofftype-listener) +* [`Benchmark.Suite.prototype.on`](#benchmarkprototypeontype-listener) +* [`Benchmark.Suite.prototype.pluck`](#benchmarksuiteprototypepluckproperty) +* [`Benchmark.Suite.prototype.pop`](#benchmarksuiteprototypepop) +* [`Benchmark.Suite.prototype.push`](#benchmarksuiteprototypepush) +* [`Benchmark.Suite.prototype.reduce`](#benchmarksuiteprototypereducecallback-accumulator) +* [`Benchmark.Suite.prototype.reset`](#benchmarksuiteprototypereset) +* [`Benchmark.Suite.prototype.reverse`](#benchmarksuiteprototypereverse) +* [`Benchmark.Suite.prototype.run`](#benchmarksuiteprototyperunoptions) +* [`Benchmark.Suite.prototype.shift`](#benchmarksuiteprototypeshift) +* [`Benchmark.Suite.prototype.slice`](#benchmarksuiteprototypeslicestart-end) +* [`Benchmark.Suite.prototype.sort`](#benchmarksuiteprototypesortcomparefnnull) +* [`Benchmark.Suite.prototype.splice`](#benchmarksuiteprototypesplicestart-deletecount--val1-val2-) +* [`Benchmark.Suite.prototype.unshift`](#benchmarksuiteprototypeunshift) + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Suite.options` +* [`Benchmark.Suite.options`](#benchmarksuiteoptions) +* [`Benchmark.Suite.options.name`](#benchmarksuiteoptionsname) + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + + +<!-- div --> + +## `Benchmark` + +<!-- div --> + +### <a id="benchmarkname-fn--options"></a>`Benchmark(name, fn [, options={}])` +<a href="#benchmarkname-fn--options">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L404 "View in source") [Ⓣ][1] + +The Benchmark constructor. + +#### Arguments +1. `name` *(String)*: A name to identify the benchmark. +2. `fn` *(Function|String)*: The test to benchmark. +3. `[options={}]` *(Object)*: Options object. + +#### Example +```js +// basic usage (the `new` operator is optional) +var bench = new Benchmark(fn); + +// or using a name first +var bench = new Benchmark('foo', fn); + +// or with options +var bench = new Benchmark('foo', fn, { + + // displayed by Benchmark#toString if `name` is not available + 'id': 'xyz', + + // called when the benchmark starts running + 'onStart': onStart, + + // called after each run cycle + 'onCycle': onCycle, + + // called when aborted + 'onAbort': onAbort, + + // called when a test errors + 'onError': onError, + + // called when reset + 'onReset': onReset, + + // called when the benchmark completes running + 'onComplete': onComplete, + + // compiled/called before the test loop + 'setup': setup, + + // compiled/called after the test loop + 'teardown': teardown +}); + +// or name and options +var bench = new Benchmark('foo', { + + // a flag to indicate the benchmark is deferred + 'defer': true, + + // benchmark test function + 'fn': function(deferred) { + // call resolve() when the deferred test is finished + deferred.resolve(); + } +}); + +// or options only +var bench = new Benchmark({ + + // benchmark name + 'name': 'foo', + + // benchmark test as a string + 'fn': '[1,2,3,4].sort()' +}); + +// a test's `this` binding is set to the benchmark instance +var bench = new Benchmark('foo', function() { + 'My name is '.concat(this.name); // My name is foo +}); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkversion"></a>`Benchmark.version` +<a href="#benchmarkversion">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3268 "View in source") [Ⓣ][1] + +*(String)*: The semantic version number. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkdeepclonevalue"></a>`Benchmark.deepClone(value)` +<a href="#benchmarkdeepclonevalue">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1225 "View in source") [Ⓣ][1] + +A deep clone utility. + +#### Arguments +1. `value` *(Mixed)*: The value to clone. + +#### Returns +*(Mixed)*: The cloned value. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkeachobject-callback-thisarg"></a>`Benchmark.each(object, callback, thisArg)` +<a href="#benchmarkeachobject-callback-thisarg">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1400 "View in source") [Ⓣ][1] + +An iteration utility for arrays and objects. Callbacks may terminate the loop by explicitly returning `false`. + +#### Arguments +1. `object` *(Array|Object)*: The object to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `thisArg` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array, Object)*: Returns the object iterated over. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkextenddestination--source"></a>`Benchmark.extend(destination [, source={}])` +<a href="#benchmarkextenddestination--source">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1446 "View in source") [Ⓣ][1] + +Copies enumerable properties from the source(s) object to the destination object. + +#### Arguments +1. `destination` *(Object)*: The destination object. +2. `[source={}]` *(Object)*: The source object. + +#### Returns +*(Object)*: The destination object. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkfilterarray-callback-thisarg"></a>`Benchmark.filter(array, callback, thisArg)` +<a href="#benchmarkfilterarray-callback-thisarg">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1485 "View in source") [Ⓣ][1] + +A generic `Array#filter` like method. + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `callback` *(Function|String)*: The function/alias called per iteration. +3. `thisArg` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: A new array of values that passed callback filter. + +#### Example +```js +// get odd numbers +Benchmark.filter([1, 2, 3, 4, 5], function(n) { + return n % 2; +}); // -> [1, 3, 5]; + +// get fastest benchmarks +Benchmark.filter(benches, 'fastest'); + +// get slowest benchmarks +Benchmark.filter(benches, 'slowest'); + +// get benchmarks that completed without erroring +Benchmark.filter(benches, 'successful'); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkforeacharray-callback-thisarg"></a>`Benchmark.forEach(array, callback, thisArg)` +<a href="#benchmarkforeacharray-callback-thisarg">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1518 "View in source") [Ⓣ][1] + +A generic `Array#forEach` like method. Callbacks may terminate the loop by explicitly returning `false`. + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `thisArg` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: Returns the array iterated over. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkformatnumbernumber"></a>`Benchmark.formatNumber(number)` +<a href="#benchmarkformatnumbernumber">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1557 "View in source") [Ⓣ][1] + +Converts a number to a more readable comma-separated string representation. + +#### Arguments +1. `number` *(Number)*: The number to convert. + +#### Returns +*(String)*: The more readable string representation. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkforownobject-callback-thisarg"></a>`Benchmark.forOwn(object, callback, thisArg)` +<a href="#benchmarkforownobject-callback-thisarg">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1545 "View in source") [Ⓣ][1] + +Iterates over an object's own properties, executing the `callback` for each. Callbacks may terminate the loop by explicitly returning `false`. + +#### Arguments +1. `object` *(Object)*: The object to iterate over. +2. `callback` *(Function)*: The function executed per own property. +3. `thisArg` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Object)*: Returns the object iterated over. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkhaskeyobject-key"></a>`Benchmark.hasKey(object, key)` +<a href="#benchmarkhaskeyobject-key">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1572 "View in source") [Ⓣ][1] + +Checks if an object has the specified key as a direct property. + +#### Arguments +1. `object` *(Object)*: The object to check. +2. `key` *(String)*: The key to check for. + +#### Returns +*(Boolean)*: Returns `true` if key is a direct property, else `false`. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkindexofarray-value--fromindex0"></a>`Benchmark.indexOf(array, value [, fromIndex=0])` +<a href="#benchmarkindexofarray-value--fromindex0">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1608 "View in source") [Ⓣ][1] + +A generic `Array#indexOf` like method. + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `value` *(Mixed)*: The value to search for. +3. `[fromIndex=0]` *(Number)*: The index to start searching from. + +#### Returns +*(Number)*: The index of the matched value or `-1`. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkinterpolatestring-object"></a>`Benchmark.interpolate(string, object)` +<a href="#benchmarkinterpolatestring-object">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1630 "View in source") [Ⓣ][1] + +Modify a string by replacing named tokens with matching object property values. + +#### Arguments +1. `string` *(String)*: The string to modify. +2. `object` *(Object)*: The template object. + +#### Returns +*(String)*: The modified string. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkinvokebenches-name--arg1-arg2-"></a>`Benchmark.invoke(benches, name [, arg1, arg2, ...])` +<a href="#benchmarkinvokebenches-name--arg1-arg2-">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1677 "View in source") [Ⓣ][1] + +Invokes a method on all items in an array. + +#### Arguments +1. `benches` *(Array)*: Array of benchmarks to iterate over. +2. `name` *(String|Object)*: The name of the method to invoke OR options object. +3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the method with. + +#### Returns +*(Array)*: A new array of values returned from each method invoked. + +#### Example +```js +// invoke `reset` on all benchmarks +Benchmark.invoke(benches, 'reset'); + +// invoke `emit` with arguments +Benchmark.invoke(benches, 'emit', 'complete', listener); + +// invoke `run(true)`, treat benchmarks as a queue, and register invoke callbacks +Benchmark.invoke(benches, { + + // invoke the `run` method + 'name': 'run', + + // pass a single argument + 'args': true, + + // treat as queue, removing benchmarks from front of `benches` until empty + 'queued': true, + + // called before any benchmarks have been invoked. + 'onStart': onStart, + + // called between invoking benchmarks + 'onCycle': onCycle, + + // called after all benchmarks have been invoked. + 'onComplete': onComplete +}); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkjoinobject--separator1--separator2:"></a>`Benchmark.join(object [, separator1=',', separator2=': '])` +<a href="#benchmarkjoinobject--separator1--separator2:">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1831 "View in source") [Ⓣ][1] + +Creates a string of joined array values or object key-value pairs. + +#### Arguments +1. `object` *(Array|Object)*: The object to operate on. +2. `[separator1=',']` *(String)*: The separator used between key-value pairs. +3. `[separator2=': ']` *(String)*: The separator used between keys and values. + +#### Returns +*(String)*: The joined result. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkmaparray-callback-thisarg"></a>`Benchmark.map(array, callback, thisArg)` +<a href="#benchmarkmaparray-callback-thisarg">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1853 "View in source") [Ⓣ][1] + +A generic `Array#map` like method. + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `thisArg` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: A new array of values returned by the callback. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkpluckarray-property"></a>`Benchmark.pluck(array, property)` +<a href="#benchmarkpluckarray-property">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1869 "View in source") [Ⓣ][1] + +Retrieves the value of a specified property from all items in an array. + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `property` *(String)*: The property to pluck. + +#### Returns +*(Array)*: A new array of property values. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkreducearray-callback-accumulator"></a>`Benchmark.reduce(array, callback, accumulator)` +<a href="#benchmarkreducearray-callback-accumulator">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1885 "View in source") [Ⓣ][1] + +A generic `Array#reduce` like method. + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `accumulator` *(Mixed)*: Initial value of the accumulator. + +#### Returns +*(Mixed)*: The accumulator. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype` + +<!-- div --> + +### <a id="benchmarkprototypeaborted"></a>`Benchmark.prototype.aborted` +<a href="#benchmarkprototypeaborted">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3378 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate if the benchmark is aborted. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypecompiled"></a>`Benchmark.prototype.compiled` +<a href="#benchmarkprototypecompiled">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3354 "View in source") [Ⓣ][1] + +*(Function, String)*: The compiled test function. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypecount"></a>`Benchmark.prototype.count` +<a href="#benchmarkprototypecount">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3330 "View in source") [Ⓣ][1] + +*(Number)*: The number of times a test was executed. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypecycles"></a>`Benchmark.prototype.cycles` +<a href="#benchmarkprototypecycles">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3338 "View in source") [Ⓣ][1] + +*(Number)*: The number of cycles performed while benchmarking. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypefn"></a>`Benchmark.prototype.fn` +<a href="#benchmarkprototypefn">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3370 "View in source") [Ⓣ][1] + +*(Function, String)*: The test to benchmark. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypehz"></a>`Benchmark.prototype.hz` +<a href="#benchmarkprototypehz">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3346 "View in source") [Ⓣ][1] + +*(Number)*: The number of executions per second. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototyperunning"></a>`Benchmark.prototype.running` +<a href="#benchmarkprototyperunning">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3386 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate if the benchmark is running. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypesetup"></a>`Benchmark.prototype.setup` +<a href="#benchmarkprototypesetup">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3449 "View in source") [Ⓣ][1] + +*(Function, String)*: Compiled into the test and executed immediately **before** the test loop. + +#### Example +```js +// basic usage +var bench = Benchmark({ + 'setup': function() { + var c = this.count, + element = document.getElementById('container'); + while (c--) { + element.appendChild(document.createElement('div')); + } + }, + 'fn': function() { + element.removeChild(element.lastChild); + } +}); + +// compiles to something like: +var c = this.count, + element = document.getElementById('container'); +while (c--) { + element.appendChild(document.createElement('div')); +} +var start = new Date; +while (count--) { + element.removeChild(element.lastChild); +} +var end = new Date - start; + +// or using strings +var bench = Benchmark({ + 'setup': '\ + var a = 0;\n\ + (function() {\n\ + (function() {\n\ + (function() {', + 'fn': 'a += 1;', + 'teardown': '\ + }())\n\ + }())\n\ + }())' +}); + +// compiles to something like: +var a = 0; +(function() { + (function() { + (function() { + var start = new Date; + while (count--) { + a += 1; + } + var end = new Date - start; + }()) + }()) +}()) +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeteardown"></a>`Benchmark.prototype.teardown` +<a href="#benchmarkprototypeteardown">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3457 "View in source") [Ⓣ][1] + +*(Function, String)*: Compiled into the test and executed immediately **after** the test loop. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeabort"></a>`Benchmark.prototype.abort()` +<a href="#benchmarkprototypeabort">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2218 "View in source") [Ⓣ][1] + +Aborts the benchmark without recording times. + +#### Returns +*(Object)*: The benchmark instance. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypecloneoptions"></a>`Benchmark.prototype.clone(options)` +<a href="#benchmarkprototypecloneoptions">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2257 "View in source") [Ⓣ][1] + +Creates a new benchmark using the same test and options. + +#### Arguments +1. `options` *(Object)*: Options object to overwrite cloned options. + +#### Returns +*(Object)*: The new benchmark instance. + +#### Example +```js +var bizarro = bench.clone({ + 'name': 'doppelganger' +}); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypecompareother"></a>`Benchmark.prototype.compare(other)` +<a href="#benchmarkprototypecompareother">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2280 "View in source") [Ⓣ][1] + +Determines if a benchmark is faster than another. + +#### Arguments +1. `other` *(Object)*: The benchmark to compare. + +#### Returns +*(Number)*: Returns `-1` if slower, `1` if faster, and `0` if indeterminate. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeemittype"></a>`Benchmark.Suite.prototype.emit(type)` +<a href="#benchmarkprototypeemittype">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2095 "View in source") [Ⓣ][1] + +Executes all registered listeners of the specified event type. + +#### Arguments +1. `type` *(String|Object)*: The event type or object. + +#### Returns +*(Mixed)*: Returns the return value of the last listener executed. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypelistenerstype"></a>`Benchmark.Suite.prototype.listeners(type)` +<a href="#benchmarkprototypelistenerstype">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2125 "View in source") [Ⓣ][1] + +Returns an array of event listeners for a given type that can be manipulated to add or remove listeners. + +#### Arguments +1. `type` *(String)*: The event type. + +#### Returns +*(Array)*: The listeners array. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeofftype-listener"></a>`Benchmark.Suite.prototype.off([type, listener])` +<a href="#benchmarkprototypeofftype-listener">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2158 "View in source") [Ⓣ][1] + +Unregisters a listener for the specified event type(s), or unregisters all listeners for the specified event type(s), or unregisters all listeners for all event types. + +#### Arguments +1. `[type]` *(String)*: The event type. +2. `[listener]` *(Function)*: The function to unregister. + +#### Returns +*(Object)*: The benchmark instance. + +#### Example +```js +// unregister a listener for an event type +bench.off('cycle', listener); + +// unregister a listener for multiple event types +bench.off('start cycle', listener); + +// unregister all listeners for an event type +bench.off('cycle'); + +// unregister all listeners for multiple event types +bench.off('start cycle complete'); + +// unregister all listeners for all event types +bench.off(); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeontype-listener"></a>`Benchmark.Suite.prototype.on(type, listener)` +<a href="#benchmarkprototypeontype-listener">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2197 "View in source") [Ⓣ][1] + +Registers a listener for the specified event type(s). + +#### Arguments +1. `type` *(String)*: The event type. +2. `listener` *(Function)*: The function to register. + +#### Returns +*(Object)*: The benchmark instance. + +#### Example +```js +// register a listener for an event type +bench.on('cycle', listener); + +// register a listener for multiple event types +bench.on('start cycle', listener); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypereset"></a>`Benchmark.prototype.reset()` +<a href="#benchmarkprototypereset">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2334 "View in source") [Ⓣ][1] + +Reset properties and abort if running. + +#### Returns +*(Object)*: The benchmark instance. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototyperunoptions"></a>`Benchmark.prototype.run([options={}])` +<a href="#benchmarkprototyperunoptions">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3000 "View in source") [Ⓣ][1] + +Runs the benchmark. + +#### Arguments +1. `[options={}]` *(Object)*: Options object. + +#### Returns +*(Object)*: The benchmark instance. + +#### Example +```js +// basic usage +bench.run(); + +// or with options +bench.run({ 'async': true }); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypetostring"></a>`Benchmark.prototype.toString()` +<a href="#benchmarkprototypetostring">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2405 "View in source") [Ⓣ][1] + +Displays relevant benchmark information when coerced to a string. + +#### Returns +*(String)*: A string representation of the benchmark instance. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.options` + +<!-- div --> + +### <a id="benchmarkoptions"></a>`Benchmark.options` +<a href="#benchmarkoptions">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3049 "View in source") [Ⓣ][1] + +*(Object)*: The default options copied by benchmark instances. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsasync"></a>`Benchmark.options.async` +<a href="#benchmarkoptionsasync">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3058 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate that benchmark cycles will execute asynchronously by default. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsdefer"></a>`Benchmark.options.defer` +<a href="#benchmarkoptionsdefer">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3066 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate that the benchmark clock is deferred. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsdelay"></a>`Benchmark.options.delay` +<a href="#benchmarkoptionsdelay">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3073 "View in source") [Ⓣ][1] + +*(Number)*: The delay between test cycles *(secs)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsid"></a>`Benchmark.options.id` +<a href="#benchmarkoptionsid">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3082 "View in source") [Ⓣ][1] + +*(String)*: Displayed by Benchmark#toString when a `name` is not available *(auto-generated if absent)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsinitcount"></a>`Benchmark.options.initCount` +<a href="#benchmarkoptionsinitcount">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3090 "View in source") [Ⓣ][1] + +*(Number)*: The default number of times to execute a test on a benchmark's first cycle. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsmaxtime"></a>`Benchmark.options.maxTime` +<a href="#benchmarkoptionsmaxtime">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3100 "View in source") [Ⓣ][1] + +*(Number)*: The maximum time a benchmark is allowed to run before finishing *(secs)*. Note: Cycle delays aren't counted toward the maximum time. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsminsamples"></a>`Benchmark.options.minSamples` +<a href="#benchmarkoptionsminsamples">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3108 "View in source") [Ⓣ][1] + +*(Number)*: The minimum sample size required to perform statistical analysis. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsmintime"></a>`Benchmark.options.minTime` +<a href="#benchmarkoptionsmintime">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3116 "View in source") [Ⓣ][1] + +*(Number)*: The time needed to reduce the percent uncertainty of measurement to `1`% *(secs)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsname"></a>`Benchmark.options.name` +<a href="#benchmarkoptionsname">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3124 "View in source") [Ⓣ][1] + +*(String)*: The name of the benchmark. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsonabort"></a>`Benchmark.options.onAbort` +<a href="#benchmarkoptionsonabort">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3132 "View in source") [Ⓣ][1] + +An event listener called when the benchmark is aborted. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsoncomplete"></a>`Benchmark.options.onComplete` +<a href="#benchmarkoptionsoncomplete">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3140 "View in source") [Ⓣ][1] + +An event listener called when the benchmark completes running. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsoncycle"></a>`Benchmark.options.onCycle` +<a href="#benchmarkoptionsoncycle">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3148 "View in source") [Ⓣ][1] + +An event listener called after each run cycle. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsonerror"></a>`Benchmark.options.onError` +<a href="#benchmarkoptionsonerror">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3156 "View in source") [Ⓣ][1] + +An event listener called when a test errors. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsonreset"></a>`Benchmark.options.onReset` +<a href="#benchmarkoptionsonreset">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3164 "View in source") [Ⓣ][1] + +An event listener called when the benchmark is reset. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkoptionsonstart"></a>`Benchmark.options.onStart` +<a href="#benchmarkoptionsonstart">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3172 "View in source") [Ⓣ][1] + +An event listener called when the benchmark starts running. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.platform` + +<!-- div --> + +### <a id="benchmarkplatform"></a>`Benchmark.platform` +<a href="#benchmarkplatform">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3183 "View in source") [Ⓣ][1] + +*(Object)*: Platform object with properties describing things like browser name, version, and operating system. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformdescription"></a>`Benchmark.platform.description` +<a href="#benchmarkplatformdescription">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3191 "View in source") [Ⓣ][1] + +*(String)*: The platform description. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformlayout"></a>`Benchmark.platform.layout` +<a href="#benchmarkplatformlayout">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3199 "View in source") [Ⓣ][1] + +*(String, Null)*: The name of the browser layout engine. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformmanufacturer"></a>`Benchmark.platform.manufacturer` +<a href="#benchmarkplatformmanufacturer">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3223 "View in source") [Ⓣ][1] + +*(String, Null)*: The name of the product's manufacturer. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformname"></a>`Benchmark.platform.name` +<a href="#benchmarkplatformname">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3215 "View in source") [Ⓣ][1] + +*(String, Null)*: The name of the browser/environment. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformos"></a>`Benchmark.platform.os` +<a href="#benchmarkplatformos">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3231 "View in source") [Ⓣ][1] + +*(String, Null)*: The name of the operating system. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformprerelease"></a>`Benchmark.platform.prerelease` +<a href="#benchmarkplatformprerelease">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3239 "View in source") [Ⓣ][1] + +*(String, Null)*: The alpha/beta release indicator. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformproduct"></a>`Benchmark.platform.product` +<a href="#benchmarkplatformproduct">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3207 "View in source") [Ⓣ][1] + +*(String, Null)*: The name of the product hosting the browser. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformversion"></a>`Benchmark.platform.version` +<a href="#benchmarkplatformversion">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3247 "View in source") [Ⓣ][1] + +*(String, Null)*: The browser/environment version. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkplatformtostring"></a>`Benchmark.platform.toString()` +<a href="#benchmarkplatformtostring">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3256 "View in source") [Ⓣ][1] + +Return platform description when the platform object is coerced to a string. + +#### Returns +*(String)*: The platform description. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.support` + +<!-- div --> + +### <a id="benchmarksupport"></a>`Benchmark.support` +<a href="#benchmarksupport">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L135 "View in source") [Ⓣ][1] + +*(Object)*: An object used to flag environments/features. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportair"></a>`Benchmark.support.air` +<a href="#benchmarksupportair">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L145 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect Adobe AIR. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportargumentsclass"></a>`Benchmark.support.argumentsClass` +<a href="#benchmarksupportargumentsclass">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L153 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if `arguments` objects have the correct internal [[Class]] value. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportbrowser"></a>`Benchmark.support.browser` +<a href="#benchmarksupportbrowser">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L161 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if in a browser environment. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportcharbyindex"></a>`Benchmark.support.charByIndex` +<a href="#benchmarksupportcharbyindex">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L169 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if strings support accessing characters by index. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportcharbyownindex"></a>`Benchmark.support.charByOwnIndex` +<a href="#benchmarksupportcharbyownindex">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L179 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if strings have indexes as own properties. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportdecompilation"></a>`Benchmark.support.decompilation` +<a href="#benchmarksupportdecompilation">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L207 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if functions support decompilation. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportdescriptors"></a>`Benchmark.support.descriptors` +<a href="#benchmarksupportdescriptors">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L228 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect ES5+ property descriptor API. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportgetallkeys"></a>`Benchmark.support.getAllKeys` +<a href="#benchmarksupportgetallkeys">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L242 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect ES5+ Object.getOwnPropertyNames(). + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportiteratesownfirst"></a>`Benchmark.support.iteratesOwnFirst` +<a href="#benchmarksupportiteratesownfirst">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L255 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if own properties are iterated before inherited properties *(all but IE < `9`)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportjava"></a>`Benchmark.support.java` +<a href="#benchmarksupportjava">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L190 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if Java is enabled/exposed. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupportnodeclass"></a>`Benchmark.support.nodeClass` +<a href="#benchmarksupportnodeclass">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L272 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if a node's [[Class]] is resolvable *(all but IE < `9`)* and that the JS engine errors when attempting to coerce an object to a string without a `toString` property value of `typeof` "function". + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksupporttimeout"></a>`Benchmark.support.timeout` +<a href="#benchmarksupporttimeout">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L198 "View in source") [Ⓣ][1] + +*(Boolean)*: Detect if the Timers API exists. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype.error` + +<!-- div --> + +### <a id="benchmarkprototypeerror"></a>`Benchmark.prototype.error` +<a href="#benchmarkprototypeerror">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3362 "View in source") [Ⓣ][1] + +*(Object)*: The error object if the test failed. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype.stats` + +<!-- div --> + +### <a id="benchmarkprototypestats"></a>`Benchmark.prototype.stats` +<a href="#benchmarkprototypestats">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3465 "View in source") [Ⓣ][1] + +*(Object)*: An object of stats including mean, margin or error, and standard deviation. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statsdeviation"></a>`Benchmark.prototype.stats.deviation` +<a href="#benchmark-statsdeviation">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3497 "View in source") [Ⓣ][1] + +*(Number)*: The sample standard deviation. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statsmean"></a>`Benchmark.prototype.stats.mean` +<a href="#benchmark-statsmean">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3505 "View in source") [Ⓣ][1] + +*(Number)*: The sample arithmetic mean. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statsmoe"></a>`Benchmark.prototype.stats.moe` +<a href="#benchmark-statsmoe">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3473 "View in source") [Ⓣ][1] + +*(Number)*: The margin of error. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statsrme"></a>`Benchmark.prototype.stats.rme` +<a href="#benchmark-statsrme">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3481 "View in source") [Ⓣ][1] + +*(Number)*: The relative margin of error *(expressed as a percentage of the mean)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statssample"></a>`Benchmark.prototype.stats.sample` +<a href="#benchmark-statssample">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3513 "View in source") [Ⓣ][1] + +*(Array)*: The array of sampled periods. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statssem"></a>`Benchmark.prototype.stats.sem` +<a href="#benchmark-statssem">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3489 "View in source") [Ⓣ][1] + +*(Number)*: The standard error of the mean. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-statsvariance"></a>`Benchmark.prototype.stats.variance` +<a href="#benchmark-statsvariance">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3521 "View in source") [Ⓣ][1] + +*(Number)*: The sample variance. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.prototype.times` + +<!-- div --> + +### <a id="benchmarkprototypetimes"></a>`Benchmark.prototype.times` +<a href="#benchmarkprototypetimes">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3530 "View in source") [Ⓣ][1] + +*(Object)*: An object of timing data including cycle, elapsed, period, start, and stop. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-timescycle"></a>`Benchmark.prototype.times.cycle` +<a href="#benchmark-timescycle">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3538 "View in source") [Ⓣ][1] + +*(Number)*: The time taken to complete the last cycle *(secs)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-timeselapsed"></a>`Benchmark.prototype.times.elapsed` +<a href="#benchmark-timeselapsed">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3546 "View in source") [Ⓣ][1] + +*(Number)*: The time taken to complete the benchmark *(secs)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-timesperiod"></a>`Benchmark.prototype.times.period` +<a href="#benchmark-timesperiod">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3554 "View in source") [Ⓣ][1] + +*(Number)*: The time taken to execute the test once *(secs)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmark-timestimestamp"></a>`Benchmark.prototype.times.timeStamp` +<a href="#benchmark-timestimestamp">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3562 "View in source") [Ⓣ][1] + +*(Number)*: A timestamp of when the benchmark started *(ms)*. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Deferred` + +<!-- div --> + +### <a id="benchmarkdeferredclone"></a>`Benchmark.Deferred(clone)` +<a href="#benchmarkdeferredclone">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L445 "View in source") [Ⓣ][1] + +The Deferred constructor. + +#### Arguments +1. `clone` *(Object)*: The cloned benchmark instance. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Deferred.prototype` + +<!-- div --> + +### <a id="benchmarkdeferredprototypebenchmark"></a>`Benchmark.Deferred.prototype.benchmark` +<a href="#benchmarkdeferredprototypebenchmark">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3606 "View in source") [Ⓣ][1] + +*(Object)*: The deferred benchmark instance. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkdeferredprototypecycles"></a>`Benchmark.Deferred.prototype.cycles` +<a href="#benchmarkdeferredprototypecycles">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3614 "View in source") [Ⓣ][1] + +*(Number)*: The number of deferred cycles performed while benchmarking. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkdeferredprototypeelapsed"></a>`Benchmark.Deferred.prototype.elapsed` +<a href="#benchmarkdeferredprototypeelapsed">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3622 "View in source") [Ⓣ][1] + +*(Number)*: The time taken to complete the deferred benchmark *(secs)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkdeferredprototyperesolve"></a>`Benchmark.Deferred.prototype.resolve` +<a href="#benchmarkdeferredprototyperesolve">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1188 "View in source") [Ⓣ][1] + +*(Unknown)*: Handles cycling/completing the deferred benchmark. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkdeferredprototypetimestamp"></a>`Benchmark.Deferred.prototype.timeStamp` +<a href="#benchmarkdeferredprototypetimestamp">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3630 "View in source") [Ⓣ][1] + +*(Number)*: A timestamp of when the deferred benchmark started *(ms)*. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event` + +<!-- div --> + +### <a id="benchmarkeventtype"></a>`Benchmark.Event(type)` +<a href="#benchmarkeventtype">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L461 "View in source") [Ⓣ][1] + +The Event constructor. + +#### Arguments +1. `type` *(String|Object)*: The event type. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event.prototype` + +<!-- div --> + +### <a id="benchmarkeventprototypeaborted"></a>`Benchmark.Event.prototype.aborted` +<a href="#benchmarkeventprototypeaborted">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3646 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate if the emitters listener iteration is aborted. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkeventprototypecancelled"></a>`Benchmark.Event.prototype.cancelled` +<a href="#benchmarkeventprototypecancelled">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3654 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate if the default action is cancelled. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkeventprototyperesult"></a>`Benchmark.Event.prototype.result` +<a href="#benchmarkeventprototyperesult">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3670 "View in source") [Ⓣ][1] + +*(Mixed)*: The return value of the last executed listener. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkeventprototypetimestamp"></a>`Benchmark.Event.prototype.timeStamp` +<a href="#benchmarkeventprototypetimestamp">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3686 "View in source") [Ⓣ][1] + +*(Number)*: A timestamp of when the event was created *(ms)*. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkeventprototypetype"></a>`Benchmark.Event.prototype.type` +<a href="#benchmarkeventprototypetype">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3694 "View in source") [Ⓣ][1] + +*(String)*: The event type. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event.prototype.currentTarget` + +<!-- div --> + +### <a id="benchmarkeventprototypecurrenttarget"></a>`Benchmark.Event.prototype.currentTarget` +<a href="#benchmarkeventprototypecurrenttarget">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3662 "View in source") [Ⓣ][1] + +*(Object)*: The object whose listeners are currently being processed. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Event.prototype.target` + +<!-- div --> + +### <a id="benchmarkeventprototypetarget"></a>`Benchmark.Event.prototype.target` +<a href="#benchmarkeventprototypetarget">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3678 "View in source") [Ⓣ][1] + +*(Object)*: The object to which the event was originally emitted. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Suite` + +<!-- div --> + +### <a id="benchmarksuitename--options"></a>`Benchmark.Suite(name [, options={}])` +<a href="#benchmarksuitename--options">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L507 "View in source") [Ⓣ][1] + +The Suite constructor. + +#### Arguments +1. `name` *(String)*: A name to identify the suite. +2. `[options={}]` *(Object)*: Options object. + +#### Example +```js +// basic usage (the `new` operator is optional) +var suite = new Benchmark.Suite; + +// or using a name first +var suite = new Benchmark.Suite('foo'); + +// or with options +var suite = new Benchmark.Suite('foo', { + + // called when the suite starts running + 'onStart': onStart, + + // called between running benchmarks + 'onCycle': onCycle, + + // called when aborted + 'onAbort': onAbort, + + // called when a test errors + 'onError': onError, + + // called when reset + 'onReset': onReset, + + // called when the suite completes running + 'onComplete': onComplete +}); +``` + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Suite.prototype` + +<!-- div --> + +### <a id="benchmarksuiteprototypeaborted"></a>`Benchmark.Suite.prototype.aborted` +<a href="#benchmarksuiteprototypeaborted">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3735 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate if the suite is aborted. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypelength"></a>`Benchmark.Suite.prototype.length` +<a href="#benchmarksuiteprototypelength">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3727 "View in source") [Ⓣ][1] + +*(Number)*: The number of benchmarks in the suite. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototyperunning"></a>`Benchmark.Suite.prototype.running` +<a href="#benchmarksuiteprototyperunning">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3743 "View in source") [Ⓣ][1] + +*(Boolean)*: A flag to indicate if the suite is running. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeabort"></a>`Benchmark.Suite.prototype.abort()` +<a href="#benchmarksuiteprototypeabort">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1902 "View in source") [Ⓣ][1] + +Aborts all benchmarks in the suite. + +#### Returns +*(Object)*: The suite instance. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeaddname-fn--options"></a>`Benchmark.Suite.prototype.add(name, fn [, options={}])` +<a href="#benchmarksuiteprototypeaddname-fn--options">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1962 "View in source") [Ⓣ][1] + +Adds a test to the benchmark suite. + +#### Arguments +1. `name` *(String)*: A name to identify the benchmark. +2. `fn` *(Function|String)*: The test to benchmark. +3. `[options={}]` *(Object)*: Options object. + +#### Returns +*(Object)*: The benchmark instance. + +#### Example +```js +// basic usage +suite.add(fn); + +// or using a name first +suite.add('foo', fn); + +// or with options +suite.add('foo', fn, { + 'onCycle': onCycle, + 'onComplete': onComplete +}); + +// or name and options +suite.add('foo', { + 'fn': fn, + 'onCycle': onCycle, + 'onComplete': onComplete +}); + +// or options only +suite.add({ + 'name': 'foo', + 'fn': fn, + 'onCycle': onCycle, + 'onComplete': onComplete +}); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypecloneoptions"></a>`Benchmark.Suite.prototype.clone(options)` +<a href="#benchmarksuiteprototypecloneoptions">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L1981 "View in source") [Ⓣ][1] + +Creates a new suite with cloned benchmarks. + +#### Arguments +1. `options` *(Object)*: Options object to overwrite cloned options. + +#### Returns +*(Object)*: The new suite instance. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeemittype"></a>`Benchmark.Suite.prototype.emit(type)` +<a href="#benchmarkprototypeemittype">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2095 "View in source") [Ⓣ][1] + +Executes all registered listeners of the specified event type. + +#### Arguments +1. `type` *(String|Object)*: The event type or object. + +#### Returns +*(Mixed)*: Returns the return value of the last listener executed. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypefiltercallback"></a>`Benchmark.Suite.prototype.filter(callback)` +<a href="#benchmarksuiteprototypefiltercallback">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2004 "View in source") [Ⓣ][1] + +An `Array#filter` like method. + +#### Arguments +1. `callback` *(Function|String)*: The function/alias called per iteration. + +#### Returns +*(Object)*: A new suite of benchmarks that passed callback filter. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeforeachcallback"></a>`Benchmark.Suite.prototype.forEach(callback)` +<a href="#benchmarksuiteprototypeforeachcallback">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3753 "View in source") [Ⓣ][1] + +An `Array#forEach` like method. Callbacks may terminate the loop by explicitly returning `false`. + +#### Arguments +1. `callback` *(Function)*: The function called per iteration. + +#### Returns +*(Object)*: The suite iterated over. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeindexofvalue"></a>`Benchmark.Suite.prototype.indexOf(value)` +<a href="#benchmarksuiteprototypeindexofvalue">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3762 "View in source") [Ⓣ][1] + +An `Array#indexOf` like method. + +#### Arguments +1. `value` *(Mixed)*: The value to search for. + +#### Returns +*(Number)*: The index of the matched value or `-1`. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeinvokename--arg1-arg2-"></a>`Benchmark.Suite.prototype.invoke(name [, arg1, arg2, ...])` +<a href="#benchmarksuiteprototypeinvokename--arg1-arg2-">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3772 "View in source") [Ⓣ][1] + +Invokes a method on all benchmarks in the suite. + +#### Arguments +1. `name` *(String|Object)*: The name of the method to invoke OR options object. +2. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the method with. + +#### Returns +*(Array)*: A new array of values returned from each method invoked. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypejoinseparator-"></a>`Benchmark.Suite.prototype.join([separator=','])` +<a href="#benchmarksuiteprototypejoinseparator-">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3781 "View in source") [Ⓣ][1] + +Converts the suite of benchmarks to a string. + +#### Arguments +1. `[separator=',']` *(String)*: A string to separate each element of the array. + +#### Returns +*(String)*: The string. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypelistenerstype"></a>`Benchmark.Suite.prototype.listeners(type)` +<a href="#benchmarkprototypelistenerstype">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2125 "View in source") [Ⓣ][1] + +Returns an array of event listeners for a given type that can be manipulated to add or remove listeners. + +#### Arguments +1. `type` *(String)*: The event type. + +#### Returns +*(Array)*: The listeners array. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypemapcallback"></a>`Benchmark.Suite.prototype.map(callback)` +<a href="#benchmarksuiteprototypemapcallback">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3790 "View in source") [Ⓣ][1] + +An `Array#map` like method. + +#### Arguments +1. `callback` *(Function)*: The function called per iteration. + +#### Returns +*(Array)*: A new array of values returned by the callback. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeofftype-listener"></a>`Benchmark.Suite.prototype.off([type, listener])` +<a href="#benchmarkprototypeofftype-listener">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2158 "View in source") [Ⓣ][1] + +Unregisters a listener for the specified event type(s), or unregisters all listeners for the specified event type(s), or unregisters all listeners for all event types. + +#### Arguments +1. `[type]` *(String)*: The event type. +2. `[listener]` *(Function)*: The function to unregister. + +#### Returns +*(Object)*: The benchmark instance. + +#### Example +```js +// unregister a listener for an event type +bench.off('cycle', listener); + +// unregister a listener for multiple event types +bench.off('start cycle', listener); + +// unregister all listeners for an event type +bench.off('cycle'); + +// unregister all listeners for multiple event types +bench.off('start cycle complete'); + +// unregister all listeners for all event types +bench.off(); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarkprototypeontype-listener"></a>`Benchmark.Suite.prototype.on(type, listener)` +<a href="#benchmarkprototypeontype-listener">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2197 "View in source") [Ⓣ][1] + +Registers a listener for the specified event type(s). + +#### Arguments +1. `type` *(String)*: The event type. +2. `listener` *(Function)*: The function to register. + +#### Returns +*(Object)*: The benchmark instance. + +#### Example +```js +// register a listener for an event type +bench.on('cycle', listener); + +// register a listener for multiple event types +bench.on('start cycle', listener); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypepluckproperty"></a>`Benchmark.Suite.prototype.pluck(property)` +<a href="#benchmarksuiteprototypepluckproperty">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3799 "View in source") [Ⓣ][1] + +Retrieves the value of a specified property from all benchmarks in the suite. + +#### Arguments +1. `property` *(String)*: The property to pluck. + +#### Returns +*(Array)*: A new array of property values. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypepop"></a>`Benchmark.Suite.prototype.pop()` +<a href="#benchmarksuiteprototypepop">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3807 "View in source") [Ⓣ][1] + +Removes the last benchmark from the suite and returns it. + +#### Returns +*(Mixed)*: The removed benchmark. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypepush"></a>`Benchmark.Suite.prototype.push()` +<a href="#benchmarksuiteprototypepush">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3815 "View in source") [Ⓣ][1] + +Appends benchmarks to the suite. + +#### Returns +*(Number)*: The suite's new length. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypereducecallback-accumulator"></a>`Benchmark.Suite.prototype.reduce(callback, accumulator)` +<a href="#benchmarksuiteprototypereducecallback-accumulator">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3834 "View in source") [Ⓣ][1] + +An `Array#reduce` like method. + +#### Arguments +1. `callback` *(Function)*: The function called per iteration. +2. `accumulator` *(Mixed)*: Initial value of the accumulator. + +#### Returns +*(Mixed)*: The accumulator. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypereset"></a>`Benchmark.Suite.prototype.reset()` +<a href="#benchmarksuiteprototypereset">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2019 "View in source") [Ⓣ][1] + +Resets all benchmarks in the suite. + +#### Returns +*(Object)*: The suite instance. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypereverse"></a>`Benchmark.Suite.prototype.reverse()` +<a href="#benchmarksuiteprototypereverse">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L638 "View in source") [Ⓣ][1] + +Rearrange the host array's elements in reverse order. + +#### Returns +*(Array)*: The reversed array. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototyperunoptions"></a>`Benchmark.Suite.prototype.run([options={}])` +<a href="#benchmarksuiteprototyperunoptions">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L2056 "View in source") [Ⓣ][1] + +Runs the suite. + +#### Arguments +1. `[options={}]` *(Object)*: Options object. + +#### Returns +*(Object)*: The suite instance. + +#### Example +```js +// basic usage +suite.run(); + +// or with options +suite.run({ 'async': true, 'queued': true }); +``` + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeshift"></a>`Benchmark.Suite.prototype.shift()` +<a href="#benchmarksuiteprototypeshift">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L671 "View in source") [Ⓣ][1] + +Removes the first element of the host array and returns it. + +#### Returns +*(Mixed)*: The first element of the array. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeslicestart-end"></a>`Benchmark.Suite.prototype.slice(start, end)` +<a href="#benchmarksuiteprototypeslicestart-end">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L684 "View in source") [Ⓣ][1] + +Creates an array of the host array's elements from the start index up to, but not including, the end index. + +#### Arguments +1. `start` *(Number)*: The starting index. +2. `end` *(Number)*: The end index. + +#### Returns +*(Array)*: The new array. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypesortcomparefnnull"></a>`Benchmark.Suite.prototype.sort([compareFn=null])` +<a href="#benchmarksuiteprototypesortcomparefnnull">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3824 "View in source") [Ⓣ][1] + +Sorts the benchmarks of the suite. + +#### Arguments +1. `[compareFn=null]` *(Function)*: A function that defines the sort order. + +#### Returns +*(Object)*: The sorted suite. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypesplicestart-deletecount--val1-val2-"></a>`Benchmark.Suite.prototype.splice(start, deleteCount [, val1, val2, ...])` +<a href="#benchmarksuiteprototypesplicestart-deletecount--val1-val2-">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L714 "View in source") [Ⓣ][1] + +Allows removing a range of elements and/or inserting elements into the host array. + +#### Arguments +1. `start` *(Number)*: The start index. +2. `deleteCount` *(Number)*: The number of elements to delete. +3. `[val1, val2, ...]` *(Mixed)*: values to insert at the `start` index. + +#### Returns +*(Array)*: An array of removed elements. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteprototypeunshift"></a>`Benchmark.Suite.prototype.unshift()` +<a href="#benchmarksuiteprototypeunshift">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L749 "View in source") [Ⓣ][1] + +Appends arguments to the host array. + +#### Returns +*(Number)*: The new length. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- div --> + +## `Benchmark.Suite.options` + +<!-- div --> + +### <a id="benchmarksuiteoptions"></a>`Benchmark.Suite.options` +<a href="#benchmarksuiteoptions">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3706 "View in source") [Ⓣ][1] + +*(Object)*: The default options copied by suite instances. + +* * * + +<!-- /div --> + + +<!-- div --> + +### <a id="benchmarksuiteoptionsname"></a>`Benchmark.Suite.options.name` +<a href="#benchmarksuiteoptionsname">#</a> [Ⓢ](https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js#L3714 "View in source") [Ⓣ][1] + +*(String)*: The name of the suite. + +* * * + +<!-- /div --> + + +<!-- /div --> + + +<!-- /div --> + + + [1]: #Benchmark "Jump back to the TOC."
\ No newline at end of file diff --git a/web/src/vendor/benchmark/doc/parse.php b/web/src/vendor/benchmark/doc/parse.php new file mode 100644 index 00000000..565b78fb --- /dev/null +++ b/web/src/vendor/benchmark/doc/parse.php @@ -0,0 +1,35 @@ +<?php + + // cleanup requested filepath + $file = isset($_GET['f']) ? $_GET['f'] : 'benchmark'; + $file = preg_replace('#(\.*[\/])+#', '', $file); + $file .= preg_match('/\.[a-z]+$/', $file) ? '' : '.js'; + + // output filename + if (isset($_GET['o'])) { + $output = $_GET['o']; + } else if (isset($_SERVER['argv'][1])) { + $output = $_SERVER['argv'][1]; + } else { + $output = basename($file); + } + + /*--------------------------------------------------------------------------*/ + + require('../vendor/docdown/docdown.php'); + + // generate Markdown + $markdown = docdown(array( + 'path' => '../' . $file, + 'title' => 'Benchmark.js <sup>v1.0.0</sup>', + 'url' => 'https://github.com/bestiejs/benchmark.js/blob/master/benchmark.js' + )); + + // save to a .md file + file_put_contents($output . '.md', $markdown); + + // print + header('Content-Type: text/plain;charset=utf-8'); + echo $markdown . PHP_EOL; + +?> diff --git a/web/src/vendor/benchmark/example/jsperf/index.html b/web/src/vendor/benchmark/example/jsperf/index.html new file mode 100644 index 00000000..040ddb63 --- /dev/null +++ b/web/src/vendor/benchmark/example/jsperf/index.html @@ -0,0 +1,287 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta name="description" content="This is just a test document for Benchmark.js."> + <title>Benchmark.js test page | jsPerf</title> + <!-- http://jsperf.com/benchmark-js-test-page --> + <link rel="stylesheet" href="main.css"> + <script>document.documentElement.className = 'js'</script> + <!--[if lt IE 9]><script src="https://raw.github.com/bestiejs/html5.js/master/html5.js"></script><![endif]--> + </head> + <body> + <article> + <hgroup> + <h1>Benchmark.js test page</h1> + <h2>JavaScript performance comparison</h2> + </hgroup> + + <p class="meta"> + Test case created by <a href="http://mathiasbynens.be/">Mathias</a> + <time datetime="2010-08-02T18:45:23+02:00" pubdate>40 seconds ago</time> + and last updated <time datetime="2010-08-02T18:45:51+02:00">12 seconds ago</time> + </p> + + <section> + <h2>Info</h2> + <p> + This is just a test document for Benchmark.js. + </p> + </section> + + <section id="prep-code"> + <h2>Preparation code</h2> + <pre><code><span + class="sc2"><<span class="kw2">div</span>></span>Lorem ipsum<span + class="sc2"><<span class="sy0">/</span><span class="kw2">div</span>></span><br><span + class="sc2"><<span class="kw2">script</span>></span><br> <span + class="kw2">var</span> arr <span class="sy0">=</span> <span class="br0">[</span><span + class="nu0">1</span><span class="sy0">,</span> <span class="nu0">5</span><span + class="sy0">,</span> <span class="nu0">4</span><span class="sy0">,</span> <span + class="nu0">2</span><span class="sy0">,</span> <span class="nu0">3</span><span + class="br0">]</span><span class="sy0">;</span><br><br> <span + class="kw2">function</span> init<span class="br0">(</span><span + class="br0">)</span> <span class="br0">{</span><br> window.<span + class="me1">console</span> <span class="sy0">&&</span> console.<span + class="me1">log</span><span class="br0">(</span><span class="st0">'init called'</span><span + class="br0">)</span><span class="sy0">;</span><br> <span + class="br0">}</span><br><span class="sc2"><<span class="sy0">/</span><span + class="kw2">script</span>></span><br><span class="sc2"><<span + class="kw2">script</span>></span><br>Benchmark.<span class="me1">prototype</span>.<span + class="me1">setup</span> <span class="sy0">=</span> <span class="kw2">function</span><span + class="br0">(</span><span class="br0">)</span> <span class="br0">{</span><br> window.<span + class="me1">foo</span> <span class="sy0">=</span> <span class="nu0">42</span><span + class="sy0">;</span><br> <span class="kw2">var</span> x <span + class="sy0">=</span> arr<span class="sy0">;</span><br><span class="br0">}</span><span + class="sy0">;</span><br><br>Benchmark.<span class="me1">prototype</span>.<span + class="me1">teardown</span> <span class="sy0">=</span> <span class="kw2">function</span><span + class="br0">(</span><span class="br0">) </span><span class="br0">{</span><br> window.<span + class="me1">foo</span> <span class="sy0">=</span> <span class="nu0">24</span><span + class="sy0">;</span><br><span class="br0">}</span><span class="sy0">;</span><br><span + class="sc2"><<span class="sy0">/</span><span class="kw2">script</span>></span></code></pre> + </section> + + <section> + <h2>Preparation code output</h2> + <div class="user-output"> + <div>Lorem ipsum</div> + </div> + </section> + + <section id="runner"> + <h2>Test runner</h2> + <p id="firebug"> + <strong>Warning! For accurate results, please disable Firebug before running the tests. <a href="http://jsperf.com/faq#firebug-warning">(Why?)</a></strong> + </p> + <p id="java"> + <strong>Java applet disabled.</strong> + </p> + <p id="status"> + <noscript> + <strong>To run the tests, please <a href="http://enable-javascript.com/">enable JavaScript</a> and reload the page.</strong> + </noscript> + </p> + <div id="controls"> + <button id="run" type="button"></button> + </div> + <table id="test-table"> + <caption>Testing in <span id="user-agent"></span></caption> + <thead> + <tr> + <th colspan="2">Test</th> + <th title="Operations per second (higher is better)">Ops/sec</th> + </tr> + </thead> + <tbody> + <tr> + <th scope="row" id="title-1"> + <div>Normal</div> + </th> + <td class="code"> + <pre><code>x.<span class="me1">sort</span><span class="br0">(</span><span + class="kw2">function</span><span class="br0">(</span>a<span + class="sy0">,</span> b<span class="br0">)</span> <span + class="br0">{</span><br> <span class="kw1">return</span> a <span + class="sy0">-</span> b<span class="sy0">;</span><br><span + class="br0">}</span><span class="br0">)</span><span + class="sy0">;</span></code></pre> + </td> + <td id="results-1" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-2"> + <div>Exit Early</div> + </th> + <td class="code"> + <pre><code>x.<span class="me1">sort</span><span class="br0">(</span><span + class="kw2">function</span><span class="br0">(</span>a<span + class="sy0">,</span> b<span class="br0">)</span> <span + class="br0">{</span><br> <span class="kw1">return</span> a <span + class="sy0">-</span> b<span class="sy0">;</span><br><span + class="br0">}</span><span class="br0">)</span><span + class="sy0">;</span><br><span class="kw1">return</span><span + class="sy0">;</span></code></pre> + </td> + <td id="results-2" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-3"> + <div>Async</div> + </th> + <td class="code"> + <pre><code><strong class="co1">// async test</strong><br>setTimeout<span + class="br0">(</span><span class="kw2">function</span><span + class="br0">(</span><span class="br0">)</span> <span + class="br0">{</span><br> deferred.<span + class="me1">resolve</span><span class="br0">(</span><span + class="br0">)</span><span class="sy0">;</span><br><span + class="br0">}</span><span class="sy0">,</span> <span + class="nu0">10</span><span class="br0">)</span><span + class="sy0">;</span></code></pre> + </td> + <td id="results-3" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-4"> + <div>Error</div> + </th> + <td class="code"> + <pre><code>x.<span class="me1">foo</span><span class="br0">(</span><span + class="br0">)</span><span class="sy0">;</span> <span + class="co1">// unknown method</span></code></pre> + </td> + <td id="results-4" class="results"></td> + </tr> + <tr> + <th scope="row" id="title-5"> + <div>Comments</div> + </th> + <td class="code"> + <pre><code><span class="co1">// comments at start</span><br>x.<span + class="me1">reverse</span><span class="br0">(</span><span + class="br0">)</span>.<span class="me1">sort</span><span + class="br0">(</span><span class="kw2">function</span><span + class="br0">(</span>a<span class="sy0">,</span> b<span + class="br0">)</span> <span class="br0">{</span><br> <span + class="kw1">return</span> a <span class="sy0">-</span> b<span + class="sy0">;</span><br><span class="br0">}</span><span + class="br0">)</span><span class="sy0">;</span><br><span + class="co1">// comments at end</span></code></pre> + </td> + <td id="results-5" class="results"></td> + </tr> + </tbody> + </table> + + <p> + You can <a href="#" rel="nofollow">edit these tests or add even more tests to this page</a> + by appending <code>/edit</code> to the URL. + </p> + </section> + + <section> + <h2 id="results">Compare results of other browsers</h2> + <div id="bs-results"></div> + </section> + + <section id="comments"> + <h1>0 comments</h1> + <div id="comments-wrapper"> + <form action="#comment-form" method="post" id="comment-form"> + <fieldset> + <h2>Add a comment</h2> + <div> + <label for="author">Name <em title="This field is required">*</em></label> + <input type="text" name="author" id="author" required> + </div> + <div> + <label for="author-email">Email <em title="This field is required">*</em></label> + <label class="inline"> + <input type="email" name="author-email" id="author-email" required> (only used for Gravatar) + </label> + </div> + <div> + <label for="author-url">URL </label> + <input type="url" name="author-url" id="author-url"> + </div> + <div> + <label for="message">Message <em title="This field is required">*</em><span>Markdown syntax is allowed</span></label> + <textarea name="message" id="message" required></textarea> + </div> + <div class="question"> + <label for="question">Are you a spammer? <span>(just answer the question)</span></label> + <input type="text" name="question" id="question"> + </div> + <div class="buttons"> + <input type="submit" class="submit" value="Add comment"> + </div> + </fieldset> + </form> + </div> + </section> + </article> + + <footer> + © 2011 <a href="http://jsperf.com/">jsPerf.com</a> + · <a href="http://jsperf.com/browse">Browse</a> + · <a href="http://jsperf.com/popular">Popular tests</a> + · <a href="http://jsperf.com/faq">FAQ</a> + · <a href="http://jsperf.com/faq#donate">Donate</a> + · <a href="http://twitter.com/jsprf" rel="nofollow">twitter: @jsprf</a> + · <a href="http://benchmarkjs.com/">Benchmark.js</a> + · by <a href="http://mathiasbynens.be/" title="Mathias Bynens, front-end web developer">@mathias</a> + </footer> + + <script src="../../vendor/platform.js/platform.js"></script> + <script src="../../benchmark.js"></script> + <script src="ui.js"></script> + <script src="../../plugin/ui.browserscope.js"></script> + <script> + var arr = [1, 5, 4, 2, 3]; + + function init() { + window.console && console.log('init called'); + } + </script> + <script> + ui.browserscope.key = 'agt1YS1wcm9maWxlcnINCxIEVGVzdBjR6NELDA'; + ui.browserscope.selector = '#bs-results'; + + ui.add('Normal', '\ + x.sort(function(a, b) {\n\ + return a - b;\n\ + });' + ) + .add('Exit Early', '\ + x.sort(function(a, b) {\n\ + return a - b;\n\ + });\n\ + return;' + ) + .add('Async', { + 'defer': true, + 'fn': '\ + setTimeout(function() {\n\ + deferred.resolve();\n\ + }, 10);' + }) + .add('Error', '\ + x.foo(); // unknown method' + ) + .add('Comments', '\ + // comments at start\n\ + x.reverse().sort(function(a, b) {\n\ + return a - b;\n\ + });\n\ + // comments at end' + ); + + Benchmark.prototype.setup = '\ + window.foo = 42;\n\ + var x = arr;'; + + Benchmark.prototype.teardown = '\ + window.foo = 24;'; + </script> + </body> +</html> diff --git a/web/src/vendor/benchmark/example/jsperf/main.css b/web/src/vendor/benchmark/example/jsperf/main.css new file mode 100644 index 00000000..52d42ef9 --- /dev/null +++ b/web/src/vendor/benchmark/example/jsperf/main.css @@ -0,0 +1,588 @@ +html, body, h1, h2, h3, fieldset, #faq, #faq dt, #faq dd { + margin: 0; + padding: 0; + border: 0; +} + +table, p, ul, h1, h2, h3, #error-info, form div, #faq, .bs-rt { + margin-bottom: 1em; +} + +button, input, textarea, a, .bs-rt { + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} + +html, input, textarea, button { + font: 1em/1.5 sans-serif; +} + +html { + background: #c4c4c4; + height: 100%; +} + +body { + background: #fff; + border: solid #aaa; + border-width: 0 1px; + width: 60em; + padding: 0 2.5em; + margin: 0 auto; + min-height: 100%; +} + +a { + color: #357ab0; + padding: .2em; +} + +a:hover, a:focus { + text-decoration: none; +} + +blockquote { + margin: 0 0 1em; + border-left: 5px solid #b4b4b4; + padding-left: .5em; +} + +table { + width: 100%; + border-collapse: collapse; +} + +thead th, button:hover, button:focus, .submit:hover, .submit:focus, a:hover, a:focus, #comments .meta a:hover, #comments .meta a:focus, li.current a:hover, li.current a:focus, form h3, #comments .owner .meta { + background: #1a6ab9; + background-image: -moz-linear-gradient(top, #6ca5dd, #1a6ab9); + background-image: -o-linear-gradient(top, #6ca5dd, #1a6ab9); + background-image: -webkit-gradient(linear, left top, left bottom, from(#6ca5dd), to(#1a6ab9)); + background-image: -webkit-linear-gradient(#6ca5dd, #1a6ab9); + background-image: linear-gradient(top, #6ca5dd, #1a6ab9); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#6ca5dd', EndColorStr='#1a6ab9'); + color: #fff; +} + +caption, #comments .meta { + background: #bcbcbc; + background-image: -moz-linear-gradient(top, #d0d0d0, #a7a7a7); + background-image: -o-linear-gradient(top, #d0d0d0, #a7a7a7); + background-image: -webkit-gradient(linear, left top, left bottom, from(#d0d0d0), to(#a7a7a7)); + background-image: -webkit-linear-gradient(#d0d0d0, #a7a7a7); + background-image: linear-gradient(top, #d0d0d0, #a7a7a7); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#d0d0d0', EndColorStr='#a7a7a7'); + color: #555; +} + +thead th, caption { + font-weight: bold; +} + +.js tbody th:hover, .js tbody th:focus { + text-decoration: underline; + cursor: pointer; +} + +tbody th, td { + border: solid #b4b4b4; + border-width: 0 1px 1px 0; +} + +tbody th { + background: #dde4ea; + min-width: 100px; +} + +tbody th div { + max-width: 200px; + word-wrap: break-word; + overflow: auto; +} + +td.results { + text-align: center; + border-right: 0; +} + +.results span, small { + display: block; + font-size: .8em; +} + +td, th, caption { + padding: .2em .5em; +} + +td.fastest { + background: #9cee82; +} + +tr:last-child td, tr:last-child th { + border-bottom: 0; +} + +td.slowest, td.error, .invalid { + background: pink; +} + +/* needs its own rule because of buggy IE */ +:focus:invalid { + background: pink; +} + +td.error { + text-transform: uppercase; + font-weight: bold; +} + +button, .submit { + padding: .35em .5em; + cursor: pointer; + color: #000; + border: 1px solid #999; + background: #dadada; + background-image: -moz-linear-gradient(top, #ebebeb, #b8b8b8); + background-image: -o-linear-gradient(top, #ebebeb, #b8b8b8); + background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#b8b8b8)); + background-image: -webkit-linear-gradient(top, #ebebeb, #b8b8b8); + background-image: linear-gradient(top, #ebebeb, #b8b8b8); + filter: progid:DXImageTransform.Microsoft.gradient(startColorStr='#ebebeb', EndColorStr='#b8b8b8'); +} + +a:hover span, a:focus span, #comments .owner .meta a { + color: #fff; +} + +#controls, #run, .buttons { + float: right; +} + +button:hover, button:focus, .submit:hover, .submit:focus { + border-color: #357ab0 +} + +#add-buttons button { + padding: .15em .4em; + font-size: 11px; + font-weight: bold; +} + +form label { + float: left; + width: 14em; + cursor: pointer; + text-align: right; + margin-right: 1em; + padding: .4em; +} + +label.inline { + float: none; + padding: 0; + margin: 0; +} + +label[for="visible"], label[for$="][defer]"] { + position: relative; + top: -.37em; +} + +label span { + display: block; + font-size: 90%; + color: #b4b4b4; +} + +label em { + color: red; + font-style: normal; +} + +.js #advanced { + display: none; +} + +#show-advanced { + display: none; +} + +.js #show-advanced { + display: block; +} + +section { + display: block; + border-top: 1px solid #ccc; + padding-top: 2em; + margin: 2em 0; +} + +textarea { + resize: vertical; + height: 15em; + width: 42.6em; + *width: 42.4em; /* IE < 8 */ +} + +input, textarea { + border: 1px solid #b4b4b4; + padding: .4em; +} + +#visible, #calibrate { /* checkboxes, for IE */ + border: 0; + padding: 0; +} + +form h2, form h3, form h4, p.error, .preview, #add-libraries, #add-buttons { + padding-left: 250px; + display: block; +} + +.js .question, hgroup h2, #controls, #firebug, #java { + display: none; +} + +pre { + width: 100%; + overflow: auto; +} + +table #results-1 { + width: 100px; +} + +table pre { + *padding: 1.5em 0; /* IE < 8 */ + *overflow-y: hidden; /* IE < 8 */ +} + +table pre, table td.code { + width: 650px; +} + +mark { + background: #ff9; + padding: .2em .1em; +} + +h1, h2, h3, h4 { + font-weight: bold; + font-size: 1em; +} + +h1 { + padding-top: 1em; + font-size: 1.4em; +} + +form h3 { + padding-top: .2em; + padding-bottom: .2em; +} + +h1 em { + font-style: normal; +} + +h1 strong { + font-style: italic; + font-family: Monaco, 'Lucida Console', monospace; +} + +li.current a { + background: #90ee85; +} + +#donate { + display: block; + background: #ffffdc; + border: 1px solid #faa700; + padding: 1em; +} + +#donate h1 { + padding-top: 0; + font-size: 16px; +} + +#paypal { + text-align: center; +} + +footer { + display: block; + margin-top: 2em; + padding: .5em 0 1.5em; + border-top: 2px solid #c4c4c4; +} + +#add-test { + margin-right: .3em; +} + +#bs-chart { + overflow: auto; +} + +#bs-logo { + margin: 0; +} + +#bs-logo span, applet { + position: absolute; + left: -9999em; +} + +#bs-logo a { + display: block; + width: 232px; + height: 39px; + filter: none; + background: url(//www.browserscope.org/static/img/logo.png) 0 0 no-repeat; +} + +#bs-ua { + padding: .5em .5em 0; + color: #555; +} + +#bs-results .bs-rt { + font-size: 10pt; + padding: .5em; + background: #ddd; +} + +#bs-results td { + border: 1px solid #ddd; + padding: .4em; + white-space: nowrap; +} + +#bs-results .rt-ua-cur { + font-style: italic; + font-weight: bold; +} + +#bs-results .bs-rt-message { + padding: 3em; + text-align: center; + font-weight: bold; + color: #555; +} + +#bs-results .google-visualization-table-tr-head td { + white-space: normal; +} + +#controls { + margin-top: -3.35em; +} + +#comments h1 { + padding: 0; +} + +#comments .meta img { + position: absolute; + left: 0; + top: 0; + margin: 0; +} + +#comments .meta img { + top: 2px; + left: 2px; +} + +#comments .meta { + padding-left: 35px; + margin-top: 0; + width: 923px; + line-height: 30px; +} + +#comments .meta a { + font-weight: bold; + color: #555; +} + +#comments article div { + padding: 0 1em 0; +} + +#comments article { + display: block; + border: 1px solid #b4b4b4; + position: relative; + margin-bottom: 1em; +} + +/* needs its own rule (cannot be grouped with `tbody th`) because of buggy IE */ +#comments article:target { + background: #dde4ea; +} + +#error-info.show, .meta strong, #firebug strong, #java strong, #status strong { + background: pink; + border: 1px solid #b00b00; + padding: .4em; +} + +#error-info.show { + padding: .5em 1em; +} + +#error-info, code, samp, var, textarea, #slug { + font-family: Monaco, monospace; + font-size: .9em; +} + +#java strong { + background: #ffffdc; + border: 1px solid #faa700; +} + +#slug { + font-size: 1em; +} + +#faq dt { + margin-top: 1em; + font-weight: bold; +} + +#faq dt a { + display: none; +} + +#faq dt:hover a { + display: inline; +} + +#faq dt:target, #faq dt:target + dd { + background: #90ee85; + margin: 0 -.8em; + padding: 0 .8em; +} + +#faq dt:target + dd { + padding-bottom: .5em; + margin-bottom: -.5em; +} + +#faq dt:target { + margin-top: .5em; + padding-top: .5em; +} + +#firebug, #java, #status { + margin: 0 0 1em; + padding: .3em 0; +} + +#prep-code pre { + max-height: 500px; + overflow: auto; +} + +#controls.show, #firebug.show, #java.show { + display: block; +} + +.co1, .co2, .coMULTI { + font-style: italic; +} + +.error { + color: #b00b00; +} + +.imp { + color: red; +} + +.kw1, .kw3 { + color: #006; +} + +.kw2 { + color: #036; +} + +.co1, .coMULTI { + color: #060; +} + +.co2 { + color: #096; +} + +.es0 { + color: #009; +} + +.br0 { + color: #090; +} + +.sy0 { + color: #393; +} + +.st0 { + color: #36c; +} + +.nu0 { + color: #c00; +} + +.me1 { + color: #606; +} + +/* < 1051px */ +@media (max-width: 1050px) { + table pre, table td.code { + width: 550px; + } +} + +/* < 1041px */ +@media (max-width: 1040px) { + body { + margin: 0; + border: 0; + } + + body, #comments .meta { + width: 100%; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + } + +} + +/* < 801px */ +@media (max-width: 800px) { + table pre, table td.code { + width: 450px; + } +} + +/* < 681px */ +@media (max-width: 680px) { + table pre, table td.code { + width: 350px; + } +} + +/* < 651px */ +@media (max-width: 650px) { + table pre, table td.code { + width: 200px; + } +} diff --git a/web/src/vendor/benchmark/example/jsperf/ui.js b/web/src/vendor/benchmark/example/jsperf/ui.js new file mode 100644 index 00000000..8270cd66 --- /dev/null +++ b/web/src/vendor/benchmark/example/jsperf/ui.js @@ -0,0 +1,745 @@ +/*! + * ui.js + * Copyright Mathias Bynens <http://mths.be/> + * Modified by John-David Dalton <http://allyoucanleet.com/> + * Available under MIT license <http://mths.be/mit> + */ +(function(window, document) { + + /** Java applet archive path */ + var archive = '../../nano.jar'; + + /** Cache of error messages */ + var errors = []; + + /** Google Analytics account id */ + var gaId = ''; + + /** Cache of event handlers */ + var handlers = {}; + + /** A flag to indicate that the page has loaded */ + var pageLoaded = false; + + /** Benchmark results element id prefix (e.g. `results-1`) */ + var prefix = 'results-'; + + /** The element responsible for scrolling the page (assumes ui.js is just before </body>) */ + var scrollEl = document.body; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** Namespace */ + var ui = new Benchmark.Suite; + + /** Object containing various CSS class names */ + var classNames = { + // used for error styles + 'error': 'error', + // used to make content visible + 'show': 'show', + // used to reset result styles + 'results': 'results' + }; + + /** Used to flag environments/features */ + var has = { + // used for pre-populating form fields + 'localStorage': !!function() { + try { + return !localStorage.getItem(+new Date); + } catch(e) { } + }(), + // used to distinguish between a regular test page and an embedded chart + 'runner': !!$('runner') + }; + + /** Object containing various text messages */ + var texts = { + // inner text for the various run button states + 'run': { + 'again': 'Run again', + 'ready': 'Run tests', + 'running': 'Stop running' + }, + // common status values + 'status': { + 'again': 'Done. Ready to run again.', + 'ready': 'Ready to run.' + } + }; + + /** The options object for Benchmark.Suite#run */ + var runOptions = { + 'async': true, + 'queued': true + }; + + /** API shortcuts */ + var each = Benchmark.each, + extend = Benchmark.extend, + filter = Benchmark.filter, + forOwn = Benchmark.forOwn, + formatNumber = Benchmark.formatNumber, + indexOf = Benchmark.indexOf, + invoke = Benchmark.invoke, + join = Benchmark.join; + + /*--------------------------------------------------------------------------*/ + + handlers.benchmark = { + + /** + * The onCycle callback, used for onStart as well, assigned to new benchmarks. + * + * @private + */ + 'cycle': function() { + var bench = this, + size = bench.stats.sample.length; + + if (!bench.aborted) { + setStatus(bench.name + ' × ' + formatNumber(bench.count) + ' (' + + size + ' sample' + (size == 1 ? '' : 's') + ')'); + } + }, + + /** + * The onStart callback assigned to new benchmarks. + * + * @private + */ + 'start': function() { + // call user provided init() function + if (isFunction(window.init)) { + init(); + } + } + }; + + handlers.button = { + + /** + * The "run" button click event handler used to run or abort the benchmarks. + * + * @private + */ + 'run': function() { + var stopped = !ui.running; + ui.abort(); + ui.length = 0; + + if (stopped) { + logError({ 'clear': true }); + ui.push.apply(ui, filter(ui.benchmarks, function(bench) { + return !bench.error && bench.reset(); + })); + ui.run(runOptions); + } + } + }; + + handlers.title = { + + /** + * The title table cell click event handler used to run the corresponding benchmark. + * + * @private + * @param {Object} event The event object. + */ + 'click': function(event) { + event || (event = window.event); + + var id, + index, + target = event.target || event.srcElement; + + while (target && !(id = target.id)) { + target = target.parentNode; + } + index = id && --id.split('-')[1] || 0; + ui.push(ui.benchmarks[index].reset()); + ui.running ? ui.render(index) : ui.run(runOptions); + }, + + /** + * The title cell keyup event handler used to simulate a mouse click when hitting the ENTER key. + * + * @private + * @param {Object} event The event object. + */ + 'keyup': function(event) { + if (13 == (event || window.event).keyCode) { + handlers.title.click(event); + } + } + }; + + handlers.window = { + + /** + * The window hashchange event handler supported by Chrome 5+, Firefox 3.6+, and IE8+. + * + * @private + */ + 'hashchange': function() { + ui.parseHash(); + + var scrollTop, + params = ui.params, + chart = params.chart, + filterBy = params.filterby; + + if (pageLoaded) { + // configure posting + ui.browserscope.postable = has.runner && !('nopost' in params); + + // configure chart renderer + if (chart || filterBy) { + scrollTop = $('results').offsetTop; + ui.browserscope.render({ 'chart': chart, 'filterBy': filterBy }); + } + if (has.runner) { + // call user provided init() function + if (isFunction(window.init)) { + init(); + } + // auto-run + if ('run' in params) { + scrollTop = $('runner').offsetTop; + setTimeout(handlers.button.run, 1); + } + // scroll to the relevant section + if (scrollTop) { + scrollEl.scrollTop = scrollTop; + } + } + } + }, + + /** + * The window load event handler used to initialize the UI. + * + * @private + */ + 'load': function() { + // only for pages with a comment form + if (has.runner) { + // init the ui + addClass('controls', classNames.show); + addListener('run', 'click', handlers.button.run); + + setHTML('run', texts.run.ready); + setHTML('user-agent', Benchmark.platform); + setStatus(texts.status.ready); + + // answer spammer question + $('question').value = 'no'; + + // prefill author details + if (has.localStorage) { + each([$('author'), $('author-email'), $('author-url')], function(element) { + element.value = localStorage[element.id] || ''; + element.oninput = element.onkeydown = function(event) { + event && event.type < 'k' && (element.onkeydown = null); + localStorage[element.id] = element.value; + }; + }); + } + // show warning when Firebug is enabled (avoids showing for Firebug Lite) + try { + // Firebug 1.9 no longer has `console.firebug` + if (console.firebug || /firebug/i.test(console.table())) { + addClass('firebug', classNames.show); + } + } catch(e) { } + } + // evaluate hash values + // (delay in an attempt to ensure this is executed after all other window load handlers) + setTimeout(function() { + pageLoaded = true; + handlers.window.hashchange(); + }, 1); + } + }; + + /*--------------------------------------------------------------------------*/ + + /** + * Shortcut for document.getElementById(). + * + * @private + * @param {Element|String} id The id of the element to retrieve. + * @returns {Element} The element, if found, or null. + */ + function $(id) { + return typeof id == 'string' ? document.getElementById(id) : id; + } + + /** + * Adds a CSS class name to an element's className property. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} className The class name. + * @returns {Element} The element. + */ + function addClass(element, className) { + if ((element = $(element)) && !hasClass(element, className)) { + element.className += (element.className ? ' ' : '') + className; + } + return element; + } + + /** + * Registers an event listener on an element. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} eventName The name of the event. + * @param {Function} handler The event handler. + * @returns {Element} The element. + */ + function addListener(element, eventName, handler) { + if ((element = $(element))) { + if (typeof element.addEventListener != 'undefined') { + element.addEventListener(eventName, handler, false); + } else if (typeof element.attachEvent != 'undefined') { + element.attachEvent('on' + eventName, handler); + } + } + return element; + } + + /** + * Appends to an element's innerHTML property. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} html The HTML to append. + * @returns {Element} The element. + */ + function appendHTML(element, html) { + if ((element = $(element)) && html != null) { + element.innerHTML += html; + } + return element; + } + + /** + * Shortcut for document.createElement(). + * + * @private + * @param {String} tag The tag name of the element to create. + * @returns {Element} A new element of the given tag name. + */ + function createElement(tagName) { + return document.createElement(tagName); + } + + /** + * Checks if an element is assigned the given class name. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} className The class name. + * @returns {Boolean} If assigned the class name return true, else false. + */ + function hasClass(element, className) { + return !!(element = $(element)) && + (' ' + element.className + ' ').indexOf(' ' + className + ' ') > -1; + } + + /** + * Set an element's innerHTML property. + * + * @private + * @param {Element|String} element The element or id of the element. + * @param {String} html The HTML to set. + * @returns {Element} The element. + */ + function setHTML(element, html) { + if ((element = $(element))) { + element.innerHTML = html == null ? '' : html; + } + return element; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Gets the Hz, i.e. operations per second, of `bench` adjusted for the + * margin of error. + * + * @private + * @param {Object} bench The benchmark object. + * @returns {Number} Returns the adjusted Hz. + */ + function getHz(bench) { + return 1 / (bench.stats.mean + bench.stats.moe); + } + + /** + * Checks if a value has an internal [[Class]] of Function. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the value is a function, else `false`. + */ + function isFunction(value) { + return toString.call(value) == '[object Function]'; + } + + /** + * Appends to or clears the error log. + * + * @private + * @param {String|Object} text The text to append or options object. + */ + function logError(text) { + var table, + div = $('error-info'), + options = {}; + + // juggle arguments + if (typeof text == 'object' && text) { + options = text; + text = options.text; + } + else if (arguments.length) { + options.text = text; + } + if (!div) { + table = $('test-table'); + div = createElement('div'); + div.id = 'error-info'; + table.parentNode.insertBefore(div, table.nextSibling); + } + if (options.clear) { + div.className = div.innerHTML = ''; + errors.length = 0; + } + if ('text' in options && indexOf(errors, text) < 0) { + errors.push(text); + addClass(div, classNames.show); + appendHTML(div, text); + } + } + + /** + * Sets the status text. + * + * @private + * @param {String} text The text to write to the status. + */ + function setStatus(text) { + setHTML('status', text); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Parses the window.location.hash value into an object assigned to `ui.params`. + * + * @static + * @memberOf ui + * @returns {Object} The suite instance. + */ + function parseHash() { + var me = this, + hashes = location.hash.slice(1).split('&'), + params = me.params || (me.params = {}); + + // remove old params + forOwn(params, function(value, key) { + delete params[key]; + }); + + // add new params + each(hashes[0] && hashes, function(value) { + value = value.split('='); + params[value[0].toLowerCase()] = (value[1] || '').toLowerCase(); + }); + return me; + } + + /** + * Renders the results table cell of the corresponding benchmark(s). + * + * @static + * @memberOf ui + * @param {Number} [index] The index of the benchmark to render. + * @returns {Object} The suite instance. + */ + function render(index) { + each(index == null ? (index = 0, ui.benchmarks) : [ui.benchmarks[index]], function(bench) { + var parsed, + cell = $(prefix + (++index)), + error = bench.error, + hz = bench.hz; + + // reset title and class + cell.title = ''; + cell.className = classNames.results; + + // status: error + if (error) { + setHTML(cell, 'Error'); + addClass(cell, classNames.error); + parsed = join(error, '</li><li>'); + logError('<p>' + error + '.</p>' + (parsed ? '<ul><li>' + parsed + '</li></ul>' : '')); + } + else { + // status: running + if (bench.running) { + setHTML(cell, 'running…'); + } + // status: completed + else if (bench.cycles) { + // obscure details until the suite has completed + if (ui.running) { + setHTML(cell, 'completed'); + } + else { + cell.title = 'Ran ' + formatNumber(bench.count) + ' times in ' + + bench.times.cycle.toFixed(3) + ' seconds.'; + setHTML(cell, formatNumber(hz.toFixed(hz < 100 ? 2 : 0)) + + ' <small>±' + bench.stats.rme.toFixed(2) + '%</small>'); + } + } + else { + // status: pending + if (ui.running && ui.indexOf(bench) > -1) { + setHTML(cell, 'pending…'); + } + // status: ready + else { + setHTML(cell, 'ready'); + } + } + } + }); + return ui; + } + + /*--------------------------------------------------------------------------*/ + + ui.on('add', function(event) { + var bench = event.target, + index = ui.benchmarks.length, + id = index + 1, + title = $('title-' + id); + + delete ui[--ui.length]; + ui.benchmarks.push(bench); + + if (has.runner) { + title.tabIndex = 0; + title.title = 'Click to run this test again.'; + + addListener(title, 'click', handlers.title.click); + addListener(title, 'keyup', handlers.title.keyup); + + bench.on('start', handlers.benchmark.start); + bench.on('start cycle', handlers.benchmark.cycle); + ui.render(index); + } + }) + .on('start cycle', function() { + ui.render(); + setHTML('run', texts.run.running); + }) + .on('complete', function() { + var benches = filter(ui.benchmarks, 'successful'), + fastest = filter(benches, 'fastest'), + slowest = filter(benches, 'slowest'); + + ui.render(); + setHTML('run', texts.run.again); + setStatus(texts.status.again); + + // highlight result cells + each(benches, function(bench) { + var cell = $(prefix + (indexOf(ui.benchmarks, bench) + 1)), + fastestHz = getHz(fastest[0]), + hz = getHz(bench), + percent = (1 - (hz / fastestHz)) * 100, + span = cell.getElementsByTagName('span')[0], + text = 'fastest'; + + if (indexOf(fastest, bench) > -1) { + // mark fastest + addClass(cell, text); + } + else { + text = isFinite(hz) + ? formatNumber(percent < 1 ? percent.toFixed(2) : Math.round(percent)) + '% slower' + : ''; + + // mark slowest + if (indexOf(slowest, bench) > -1) { + addClass(cell, 'slowest'); + } + } + // write ranking + if (span) { + setHTML(span, text); + } else { + appendHTML(cell, '<span>' + text + '</span>'); + } + }); + + ui.browserscope.post(); + }); + + /*--------------------------------------------------------------------------*/ + + /** + * An array of benchmarks created from test cases. + * + * @memberOf ui + * @type Array + */ + ui.benchmarks = []; + + /** + * The parsed query parameters of the pages url hash. + * + * @memberOf ui + * @type Object + */ + ui.params = {}; + + // parse query params into ui.params hash + ui.parseHash = parseHash; + + // (re)render the results of one or more benchmarks + ui.render = render; + + /*--------------------------------------------------------------------------*/ + + // expose + window.ui = ui; + + // don't let users alert, confirm, prompt, or open new windows + window.alert = window.confirm = window.prompt = window.open = function() { }; + + // parse hash query params when it changes + addListener(window, 'hashchange', handlers.window.hashchange); + + // bootstrap onload + addListener(window, 'load', handlers.window.load); + + // parse location hash string + ui.parseHash(); + + // provide a simple UI for toggling between chart types and filtering results + // (assumes ui.js is just before </body>) + (function() { + var sibling = $('bs-results'), + p = createElement('p'); + + p.innerHTML = + '<span id=charts><strong>Chart type:</strong> <a href=#>bar</a>, ' + + '<a href=#>column</a>, <a href=#>line</a>, <a href=#>pie</a>, ' + + '<a href=#>table</a></span><br>' + + '<span id=filters><strong>Filter:</strong> <a href=#>popular</a>, ' + + '<a href=#>all</a>, <a href=#>desktop</a>, <a href=#>family</a>, ' + + '<a href=#>major</a>, <a href=#>minor</a>, <a href=#>mobile</a>, ' + + '<a href=#>prerelease</a></span>'; + + sibling.parentNode.insertBefore(p, sibling); + + // use DOM0 event handler to simplify canceling the default action + $('charts').onclick = + $('filters').onclick = function(event) { + event || (event = window.event); + var target = event.target || event.srcElement; + if (target.href || (target = target.parentNode).href) { + ui.browserscope.render( + target.parentNode.id == 'charts' + ? { 'chart': target.innerHTML } + : { 'filterBy': target.innerHTML } + ); + } + // cancel the default action + return false; + }; + }()); + + /*--------------------------------------------------------------------------*/ + + // fork for runner or embedded chart + if (has.runner) { + // detect the scroll element + (function() { + var scrollTop, + div = document.createElement('div'), + body = document.body, + bodyStyle = body.style, + bodyHeight = bodyStyle.height, + html = document.documentElement, + htmlStyle = html.style, + htmlHeight = htmlStyle.height; + + bodyStyle.height = htmlStyle.height = 'auto'; + div.style.cssText = 'display:block;height:9001px;'; + body.insertBefore(div, body.firstChild); + scrollTop = html.scrollTop; + + // set `scrollEl` that's used in `handlers.window.hashchange()` + if (html.clientWidth !== 0 && ++html.scrollTop && html.scrollTop == scrollTop + 1) { + scrollEl = html; + } + body.removeChild(div); + bodyStyle.height = bodyHeight; + htmlStyle.height = htmlHeight; + html.scrollTop = scrollTop; + }()); + + // catch and display errors from the "preparation code" + window.onerror = function(message, fileName, lineNumber) { + logError('<p>' + message + '.</p><ul><li>' + join({ + 'message': message, + 'fileName': fileName, + 'lineNumber': lineNumber + }, '</li><li>') + '</li></ul>'); + scrollEl.scrollTop = $('error-info').offsetTop; + }; + // inject nano applet + // (assumes ui.js is just before </body>) + if ('nojava' in ui.params) { + addClass('java', classNames.show); + } else { + // using innerHTML avoids an alert in some versions of IE6 + document.body.insertBefore(setHTML(createElement('div'), + '<applet code=nano archive=' + archive + '>').lastChild, document.body.firstChild); + } + } + else { + // short circuit unusable methods + ui.render = function() { }; + ui.off('start cycle complete'); + setTimeout(function() { + ui.off(); + ui.browserscope.post = function() { }; + invoke(ui.benchmarks, 'off'); + }, 1); + } + + /*--------------------------------------------------------------------------*/ + + // optimized asynchronous Google Analytics snippet based on + // http://mathiasbynens.be/notes/async-analytics-snippet + if (gaId) { + (function() { + var script = createElement('script'), + sibling = document.getElementsByTagName('script')[0]; + + window._gaq = [['_setAccount', gaId], ['_trackPageview']]; + script.src = '//www.google-analytics.com/ga.js'; + sibling.parentNode.insertBefore(script, sibling); + }()); + } +}(this, document)); diff --git a/web/src/vendor/benchmark/nano.jar b/web/src/vendor/benchmark/nano.jar Binary files differnew file mode 100644 index 00000000..b5778403 --- /dev/null +++ b/web/src/vendor/benchmark/nano.jar diff --git a/web/src/vendor/benchmark/nano.java b/web/src/vendor/benchmark/nano.java new file mode 100644 index 00000000..96fc2244 --- /dev/null +++ b/web/src/vendor/benchmark/nano.java @@ -0,0 +1,23 @@ +/** + * Simple class to expose nanoTime() to JavaScript. + * + * Compile using + * javac -g:none -target 1.5 nano.java + * jar cfM nano.jar nano.class + * java -jar proguard.jar @options.txt + * + * ProGuard (http://proguard.sourceforge.net) + * options.txt + * -injars nano.jar + * -outjars nano_s.jar + * -libraryjars <java.home>/jre/lib/rt.jar + * -keep public class nano { + * public long nanoTime(); + * } + */ +import java.applet.Applet; +public class nano extends Applet { + public long nanoTime() { + return System.nanoTime(); + } +} diff --git a/web/src/vendor/benchmark/package.json b/web/src/vendor/benchmark/package.json new file mode 100644 index 00000000..2be940ca --- /dev/null +++ b/web/src/vendor/benchmark/package.json @@ -0,0 +1,54 @@ +{ + "name": "benchmark", + "version": "1.0.0", + "description": "A benchmarking library that works on nearly all JavaScript platforms, supports high-resolution timers, and returns statistically significant results.", + "homepage": "http://benchmarkjs.com/", + "main": "benchmark", + "keywords": [ + "benchmark", + "narwhal", + "node", + "performance", + "ringo", + "speed" + ], + "licenses": [ + { + "type": "MIT", + "url": "http://mths.be/mit" + } + ], + "author": { + "name": "Mathias Bynens", + "email": "mathias@benchmarkjs.com", + "web": "http://mathiasbynens.be/" + }, + "maintainers": [ + { + "name": "John-David Dalton", + "email": "john.david.dalton@gmail.com", + "web": "http://allyoucanleet.com/" + }, + { + "name": "Mathias Bynens", + "email": "mathias@benchmarkjs.com", + "web": "http://mathiasbynens.be/" + } + ], + "bugs": { + "email": "bugs@benchmarkjs.com", + "url": "https://github.com/bestiejs/benchmark.js/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/bestiejs/benchmark.js.git" + }, + "engines": [ + "node", + "rhino" + ], + "directories": { + "doc": "./doc", + "test": "./test" + } +} diff --git a/web/src/vendor/benchmark/plugin/ui.browserscope.js b/web/src/vendor/benchmark/plugin/ui.browserscope.js new file mode 100644 index 00000000..01905bde --- /dev/null +++ b/web/src/vendor/benchmark/plugin/ui.browserscope.js @@ -0,0 +1,1052 @@ +(function(window, document) { + + /** Cache used by various methods */ + var cache = { + 'counter': 0, + 'lastAction': 'load', + 'lastChart': 'bar', + 'lastFilterBy': 'all', + 'responses': { /* 'all': null, 'desktop': null, 'major': null, ... */ }, + 'timers': { /* 'cleanup': null, 'load': null, 'post': null, ... */ }, + 'trash': createElement('div') + }; + + /** + * Used to filter Browserscope results by browser category. + * + * @see http://www.browserscope.org/user/tests/howto#urlparams + */ + var filterMap = { + 'all': 3, + 'desktop': 'top-d', + 'family': 0, + 'major': 1, + 'minor': 2, + 'mobile': 'top-m', + 'popular': 'top', + 'prerelease': 'top-d-e' + }; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** + * The `uaToken` is prepended to the value of the data cell of the Google + * visualization data table object that matches the user's browser name. After + * the chart is rendered the element containing the `uaToken` is assigned the + * `ui.browserscope.uaClass` class name to allow for the creation of a visual + * indicator to help the user more easily find their browser's results. + */ + var uaToken = '\u2028'; + + /** Math shortcuts */ + var floor = Math.floor, + max = Math.max, + min = Math.min; + + /** Utility shortcuts */ + var each = Benchmark.each, + extend = Benchmark.extend, + filter = Benchmark.filter, + forOwn = Benchmark.forOwn, + formatNumber = Benchmark.formatNumber, + hasKey = Benchmark.hasKey, + indexOf = Benchmark.indexOf, + interpolate = Benchmark.interpolate, + invoke = Benchmark.invoke, + map = Benchmark.map, + reduce = Benchmark.reduce; + + /*--------------------------------------------------------------------------*/ + + /** + * Registers an event listener. + * + * @private + * @param {Element} element The element. + * @param {String} eventName The name of the event to listen to. + * @param {Function} handler The event handler. + * @returns {Element} The element. + */ + function addListener(element, eventName, handler) { + if ((element = typeof element == 'string' ? query(element)[0] : element)) { + if (typeof element.addEventListener != 'undefined') { + element.addEventListener(eventName, handler, false); + } else if (typeof element.attachEvent != 'undefined') { + element.attachEvent('on' + eventName, handler); + } + } + return element; + } + + /** + * Shortcut for `document.createElement()`. + * + * @private + * @param {String} tagName The tag name of the element to create. + * @param {String} name A name to assign to the element. + * @param {Document|Element} context The document object used to create the element. + * @returns {Element} Returns a new element. + */ + function createElement(tagName, name, context) { + var result; + name && name.nodeType && (context = name, name = 0); + context = context ? context.ownerDocument || context : document; + name || (name = ''); + + try { + // set name attribute for IE6/7 + result = context.createElement('<' + tagName + ' name="' + name + '">'); + } catch(e) { + (result = context.createElement(tagName)).name = name; + } + return result; + } + + /** + * Creates a new style element. + * + * @private + * @param {String} cssText The css text of the style element. + * @param {Document|Element} context The document object used to create the element. + * @returns {Element} Returns the new style element. + */ + function createStyleSheet(cssText, context) { + // use a text node, "x", to work around innerHTML issues with style elements + // http://msdn.microsoft.com/en-us/library/ms533897(v=vs.85).aspx#1 + var div = createElement('div', context); + div.innerHTML = 'x<style>' + cssText + '</style>'; + return div.lastChild; + } + + /** + * Gets the text content of an element. + * + * @private + * @param {Element} element The element. + * @returns {String} The text content of the element. + */ + function getText(element) { + element = query(element)[0]; + return element && (element.textContent || element.innerText) || ''; + } + + /** + * Injects a script into the document. + * + * @private + * @param {String} src The external script source. + * @param {Object} sibling The element to inject the script after. + * @param {Document} context The document object used to create the script element. + * @returns {Object} The new script element. + */ + function loadScript(src, sibling, context) { + context = sibling ? sibling.ownerDocument || [sibling, sibling = 0][0] : context; + var script = createElement('script', context), + nextSibling = sibling ? sibling.nextSibling : query('script', context).pop(); + + script.src = src; + return (sibling || nextSibling).parentNode.insertBefore(script, nextSibling); + } + + /** + * Queries the document for elements by id or tagName. + * + * @private + * @param {String} selector The css selector to match. + * @param {Document|Element} context The element whose descendants are queried. + * @returns {Array} The array of results. + */ + function query(selector, context) { + var result = []; + selector || (selector = ''); + context = typeof context == 'string' ? query(context)[0] : context || document; + + if (selector.nodeType) { + result = [selector]; + } + else if (context) { + each(selector.split(','), function(selector) { + each(/^#/.test(selector) + ? [context.getElementById(selector.slice(1))] + : context.getElementsByTagName(selector), function(node) { + result.push(node); + }); + }); + } + return result; + } + + /** + * Set an element's innerHTML property. + * + * @private + * @param {Element} element The element. + * @param {String} html The HTML to set. + * @param {Object} object The template object used to modify the html. + * @returns {Element} The element. + */ + function setHTML(element, html, object) { + if ((element = query(element)[0])) { + element.innerHTML = interpolate(html, object); + } + return element; + } + + /** + * Displays a message in the "results" element. + * + * @private + * @param {String} text The text to display. + * @param {Object} object The template object used to modify the text. + */ + function setMessage(text, object) { + var me = ui.browserscope, + cont = me.container; + + if (cont) { + cont.className = 'bs-rt-message'; + setHTML(cont, text, object); + } + } + + /*--------------------------------------------------------------------------*/ + + /** + * Adds a style sheet to the current chart and assigns the `ui.browserscope.uaClass` + * class name to the chart element containing the user's browser name. + * + * @private + * @returns {Boolean} Returns `true` if the operation succeeded, else `false`. + */ + function addChartStyle() { + var me = ui.browserscope, + cssText = [], + context = frames[query('iframe', me.container)[0].name].document, + chartNodes = query('text,textpath', context), + uaClass = me.uaClass, + result = false; + + if (chartNodes.length) { + // extract CSS rules for `uaClass` + each(query('link,style'), function(node) { + // avoid access denied errors on external style sheets + // outside the same origin policy + try { + var sheet = node.sheet || node.styleSheet; + each(sheet.cssRules || sheet.rules, function(rule) { + if ((rule.selectorText || rule.cssText).indexOf('.' + uaClass) > -1) { + cssText.push(rule.style && rule.style.cssText || /[^{}]*(?=})/.exec(rule.cssText) || ''); + } + }); + } catch(e) { } + }); + + // insert custom style sheet + query('head', context)[0].appendChild( + createStyleSheet('.' + uaClass + '{' + cssText.join(';') + '}', context)); + + // scan chart elements for a match + each(chartNodes, function(node) { + var nextSibling; + if ((node.string || getText(node)).charAt(0) == uaToken) { + // for VML + if (node.string) { + // IE requires reinserting the element to render correctly + node.className = uaClass; + nextSibling = node.nextSibling; + node.parentNode.insertBefore(node.removeNode(), nextSibling); + } + // for SVG + else { + node.setAttribute('class', uaClass); + } + result = true; + } + }); + } + return result; + } + + /** + * Periodically executed callback that removes injected script and iframe elements. + * + * @private + */ + function cleanup() { + var me = ui.browserscope, + timings = me.timings, + timers = cache.timers, + trash = cache.trash, + delay = timings.cleanup * 1e3; + + // remove injected scripts and old iframes when benchmarks aren't running + if (timers.cleanup && !ui.running) { + // if expired, destroy the element to prevent pseudo memory leaks. + // http://dl.dropbox.com/u/513327/removechild_ie_leak.html + each(query('iframe,script'), function(element) { + var expire = +(/^browserscope-\d+-(\d+)$/.exec(element.name) || 0)[1] + max(delay, timings.timeout * 1e3); + if (new Date > expire || /browserscope\.org|google\.com/.test(element.src)) { + trash.appendChild(element); + trash.innerHTML = ''; + } + }); + } + // schedule another round + timers.cleanup = setTimeout(cleanup, delay); + } + + /** + * A simple data object cloning utility. + * + * @private + * @param {Mixed} data The data object to clone. + * @returns {Mixed} The cloned data object. + */ + function cloneData(data) { + var fn, + ctor, + result = data; + + if (isArray(data)) { + result = map(data, cloneData); + } + else if (data === Object(data)) { + ctor = data.constructor; + result = ctor == Object ? {} : (fn = function(){}, fn.prototype = ctor.prototype, new fn); + forOwn(data, function(value, key) { + result[key] = cloneData(value); + }); + } + return result; + } + + /** + * Creates a Browserscope results object. + * + * @private + * @returns {Object|Null} Browserscope results object or null. + */ + function createSnapshot() { + // clone benches, exclude those that are errored, unrun, or have hz of Infinity + var benches = invoke(filter(ui.benchmarks, 'successful'), 'clone'), + fastest = filter(benches, 'fastest'), + slowest = filter(benches, 'slowest'), + neither = filter(benches, function(bench) { + return indexOf(fastest, bench) + indexOf(slowest, bench) == -2; + }); + + function merge(destination, source) { + destination.count = source.count; + destination.cycles = source.cycles; + destination.hz = source.hz; + destination.stats = extend({}, source.stats); + } + + // normalize results on slowest in each category + each(fastest.concat(slowest), function(bench) { + merge(bench, indexOf(fastest, bench) > -1 ? fastest[fastest.length - 1] : slowest[0]); + }); + + // sort slowest to fastest + // (a larger `mean` indicates a slower benchmark) + neither.sort(function(a, b) { + a = a.stats; b = b.stats; + return (a.mean + a.moe > b.mean + b.moe) ? -1 : 1; + }); + + // normalize the leftover benchmarks + reduce(neither, function(prev, bench) { + // if the previous slower benchmark is indistinguishable from + // the current then use the previous benchmark's values + if (prev.compare(bench) == 0) { + merge(bench, prev); + } + return bench; + }); + + // append benchmark ids for duplicate names or names with no alphanumeric/space characters + // and use the upper limit of the confidence interval to compute a lower hz + // to avoid recording inflated results caused by a high margin or error + return reduce(benches, function(result, bench, key) { + var stats = bench.stats; + result || (result = {}); + key = toLabel(bench.name); + result[key && !hasKey(result, key) ? key : key + bench.id ] = floor(1 / (stats.mean + stats.moe)); + return result; + }, null); + } + + /** + * Retrieves the "cells" array from a given Google visualization data row object. + * + * @private + * @param {Object} object The data row object. + * @returns {Array} An array of cell objects. + */ + function getDataCells(object) { + // resolve cells by duck typing because of munged property names + var result = []; + forOwn(object, function(value) { + return !(isArray(value) && (result = value)); + }); + // remove empty entries which occur when not all the tests are recorded + return filter(result, Boolean); + } + + /** + * Retrieves the "labels" array from a given Google visualization data table object. + * + * @private + * @param {Object} object The data table object. + * @returns {Array} An array of label objects. + */ + function getDataLabels(object) { + var result = [], + labelMap = {}; + + // resolve labels by duck typing because of munged property names + forOwn(object, function(value) { + return !(isArray(value) && 0 in value && 'type' in value[0] && (result = value)); + }); + // create a data map of labels to names + each(ui.benchmarks, function(bench) { + var key = toLabel(bench.name); + labelMap[key && !hasKey(labelMap, key) ? key : key + bench.id ] = bench.name; + }); + // replace Browserscope's basic labels with benchmark names + return each(result, function(cell) { + var name = labelMap[cell.label]; + name && (cell.label = name); + }); + } + + /** + * Retrieves the "rows" array from a given Google visualization data table object. + * + * @private + * @param {Object} object The data table object. + * @returns {Array} An array of row objects. + */ + function getDataRows(object) { + var name, + filterBy = cache.lastFilterBy, + browserName = toBrowserName(getText(query('strong', '#bs-ua')[0]), filterBy), + uaClass = ui.browserscope.uaClass, + result = []; + + // resolve rows by duck typing because of munged property names + forOwn(object, function(value, key) { + return !(isArray(value) && 0 in value && !('type' in value[0]) && (name = key, result = value)); + }); + // remove empty rows and set the `p.className` on the browser + // name cell that matches the user's browser name + if (result.length) { + result = object[name] = filter(result, function(value) { + var cells = getDataCells(value), + first = cells[0], + second = cells[1]; + + // cells[0] is the browser name cell so instead we check cells[1] + // for the presence of ops/sec data to determine if a row is empty or not + if (first && second && second.f) { + delete first.p.className; + if (browserName == toBrowserName(first.f, filterBy)) { + first.p.className = uaClass; + } + return true; + } + }); + } + return result; + } + + /** + * Checks if a value has an internal [[Class]] of Array. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the value has an internal [[Class]] of + * Array, else `false`. + */ + function isArray(value) { + return toString.call(value) == '[object Array]'; + } + + /** + * Executes a callback at a given delay interval until it returns `false`. + * + * @private + * @param {Function} callback The function called every poll interval. + * @param {Number} delay The delay between callback calls (secs). + */ + function poll(callback, delay) { + function poller(init) { + if (init || callback() !== false) { + setTimeout(poller, delay * 1e3); + } + } + poller(true); + } + + /** + * Cleans up the last action and sets the current action. + * + * @private + * @param {String} action The current action. + */ + function setAction(action) { + clearTimeout(cache.timers[cache.lastAction]); + cache.lastAction = action; + } + + /** + * Converts the browser name version number to the format allowed by the + * specified filter. + * + * @private + * @param {String} name The full browser name . + * @param {String} filterBy The filter formating rules to apply. + * @returns {String} The converted browser name. + */ + function toBrowserName(name, filterBy) { + name || (name = ''); + if (filterBy == 'all') { + // truncate something like 1.0.0 to 1 + name = name.replace(/(\d+)[.0]+$/, '$1'); + } + else if (filterBy == 'family') { + // truncate something like XYZ 1.2 to XYZ + name = name.replace(/[.\d\s]+$/, ''); + } + else if (/minor|popular/.test(filterBy) && /\d+(?:\.[1-9])+$/.test(name)) { + // truncate something like 1.2.3 to 1.2 + name = name.replace(/(\d+\.[1-9])(\.[.\d]+$)/, '$1'); + } + else { + // truncate something like 1.0 to 1 or 1.2.3 to 1 but leave something like 1.2 alone + name = name.replace(/(\d+)(?:(\.[1-9]$)|(\.[.\d]+$))/, '$1$2'); + } + return name; + } + + /** + * Replaces non-alphanumeric characters with spaces because Browserscope labels + * can only contain alphanumeric characters and spaces. + * + * @private + * @param {String} text The text to be converted. + * @returns {String} The Browserscope safe label text. + * @see http://code.google.com/p/browserscope/issues/detail?id=271 + */ + function toLabel(text) { + return (text || '').replace(/[^a-z0-9]+/gi, ' '); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Loads Browserscope's cumulative results table. + * + * @static + * @memberOf ui.browserscope + * @param {Object} options The options object. + */ + function load(options) { + options || (options = {}); + + var fired, + me = ui.browserscope, + cont = me.container, + filterBy = cache.lastFilterBy = options.filterBy || cache.lastFilterBy, + responses = cache.responses, + response = cache.responses[filterBy], + visualization = window.google && google.visualization; + + function onComplete(response) { + var lastResponse = responses[filterBy]; + if (!fired) { + // set the fired flag to avoid Google's own timeout + fired = true; + // render if the filter is still the same, else cache the result + if (filterBy == cache.lastFilterBy) { + me.render({ 'force': true, 'response': lastResponse || response }); + } else if(!lastResponse && response && !response.isError()) { + responses[filterBy] = response; + } + } + } + + // set last action in case the load fails and a retry is needed + setAction('load'); + + // exit early if there is no container element or the response is cached + // and retry if the visualization library hasn't loaded yet + if (!cont || !visualization || !visualization.Query || response) { + cont && onComplete(response); + } + else if (!ui.running) { + // set our own load timeout to display an error message and retry loading + cache.timers.load = setTimeout(onComplete, me.timings.timeout * 1e3); + // set "loading" message and attempt to load Browserscope data + setMessage(me.texts.loading); + // request Browserscope pass chart data to `google.visualization.Query.setResponse()` + (new visualization.Query( + '//www.browserscope.org/gviz_table_data?category=usertest_' + me.key + '&v=' + filterMap[filterBy], + { 'sendMethod': 'scriptInjection' } + )) + .send(onComplete); + } + } + + /** + * Creates a Browserscope beacon and posts the benchmark results. + * + * @static + * @memberOf ui.browserscope + */ + function post() { + var idoc, + iframe, + body = document.body, + me = ui.browserscope, + key = me.key, + timings = me.timings, + name = 'browserscope-' + (cache.counter++) + '-' + (+new Date), + snapshot = createSnapshot(); + + // set last action in case the post fails and a retry is needed + setAction('post'); + + if (key && snapshot && me.postable && !ui.running && !/Simulator/i.test(Benchmark.platform)) { + // create new beacon + // (the name contains a timestamp so `cleanup()` can determine when to remove it) + iframe = createElement('iframe', name); + body.insertBefore(iframe, body.firstChild); + idoc = frames[name].document; + iframe.style.display = 'none'; + + // expose results snapshot + me.snapshot = snapshot; + // set "posting" message and attempt to post the results snapshot + setMessage(me.texts.post); + // Note: We originally created an iframe to avoid Browerscope's old limit + // of one beacon per page load. It's currently used to implement custom + // request timeout and retry routines. + idoc.write(interpolate( + // the doctype is required so Browserscope detects the correct IE compat mode + '#{doctype}<title></title><body><script>' + + 'with(parent.ui.browserscope){' + + 'var _bTestResults=snapshot,' + + '_bC=function(){clearTimeout(_bT);parent.setTimeout(function(){purge();load()},#{refresh}*1e3)},' + + '_bT=setTimeout(function(){_bC=function(){};render()},#{timeout}*1e3)' + + '}<\/script>' + + '<script src=//www.browserscope.org/user/beacon/#{key}?callback=_bC><\/script>', + { + 'doctype': /css/i.test(document.compatMode) ? '<!doctype html>' : '', + 'key': key, + 'refresh': timings.refresh, + 'timeout': timings.timeout + } + )); + // avoid the IE spinner of doom + // http://www.google.com/search?q=IE+throbber+of+doom + idoc.close(); + } + else { + me.load(); + } + } + + /** + * Purges the Browserscope response cache. + * + * @static + * @memberOf ui.browserscope + * @param {String} key The key of a single cache entry to clear. + */ + function purge(key) { + // we don't pave the cache object with a new one to preserve existing references + var responses = cache.responses; + if (key) { + delete responses[key]; + } else { + forOwn(responses, function(value, key) { + delete responses[key]; + }); + } + } + + /** + * Renders the cumulative results table. + * (tweak the dimensions and styles to best fit your environment) + * + * @static + * @memberOf ui.browserscope + * @param {Object} options The options object. + */ + function render(options) { + options || (options = {}); + + // coordinates, dimensions, and sizes are in px + var areaHeight, + cellWidth, + data, + labels, + rowCount, + rows, + me = ui.browserscope, + cont = me.container, + responses = cache.responses, + visualization = window.google && google.visualization, + lastChart = cache.lastChart, + chart = cache.lastChart = options.chart || lastChart, + lastFilterBy = cache.lastFilterBy, + filterBy = cache.lastFilterBy = options.filterBy || lastFilterBy, + lastResponse = responses[filterBy], + response = responses[filterBy] = 'response' in options ? (response = options.response) && !response.isError() && response : lastResponse, + areaWidth = '100%', + cellHeight = 80, + fontSize = 13, + height = 'auto', + hTitle = 'operations per second (higher is better)', + hTitleHeight = 48, + left = 240, + legend = 'top', + maxChars = 0, + maxCharsLimit = 20, + maxOps = 0, + minHeight = 480, + minWidth = cont && cont.offsetWidth || 948, + title = '', + top = 50, + vTitle = '', + vTitleWidth = 48, + width = minWidth; + + function retry(force) { + var action = cache.lastAction; + if (force || ui.running) { + cache.timers[action] = setTimeout(retry, me.timings.retry * 1e3); + } else { + me[action].apply(me, action == 'render' ? [options] : []); + } + } + + // set action to clear any timeouts and prep for retries + setAction(response ? 'render' : cache.lastAction); + + // exit early if there is no container element, the data filter has changed or nothing has changed + if (!cont || visualization && (filterBy != lastFilterBy || + (!options.force && chart == lastChart && response == lastResponse))) { + cont && filterBy != lastFilterBy && load(options); + } + // retry if response data is empty/errored or the visualization library hasn't loaded yet + else if (!response || !visualization) { + // set error message for empty/errored response + !response && visualization && setMessage(me.texts.error); + retry(true); + } + // visualization chart gallary + // http://code.google.com/apis/chart/interactive/docs/gallery.html + else if (!ui.running) { + cont.className = ''; + data = cloneData(response.getDataTable()); + labels = getDataLabels(data); + rows = getDataRows(data); + rowCount = rows.length; + chart = chart.charAt(0).toUpperCase() + chart.slice(1).toLowerCase(); + + // adjust data for non-tabular displays + if (chart != 'Table') { + // remove "# Tests" run count label (without label data the row will be ignored) + labels.pop(); + + // modify row data + each(rows, function(row) { + each(getDataCells(row), function(cell, index, cells) { + var lastIndex = cells.length - 1; + + // cells[1] through cells[lastIndex - 1] are ops/sec cells + if (/^[\d.,]+$/.test(cell.f)) { + // assign ops/sec as cell value + cell.v = +cell.f.replace(/,/g, ''); + // add rate to the text + cell.f += ' ops/sec'; + // capture highest ops value to use when computing the left coordinate + maxOps = max(maxOps, cell.v); + } + // cells[0] is the browser name cell + // cells[lastIndex] is the run count cell and has no `f` property + else if (cell.f) { + // add test run count to browser name + cell.f += chart == 'Pie' ? '' : ' (' + (cells[lastIndex].v || 1) + ')'; + // capture longest char count to use when computing left coordinate/cell width + maxChars = min(maxCharsLimit, max(maxChars, cell.f.length)); + } + // compute sum of all ops/sec for pie charts + if (chart == 'Pie') { + if (index == lastIndex) { + cells[1].f = formatNumber(cells[1].v) + ' total ops/sec'; + } else if (index > 1 && typeof cell.v == 'number') { + cells[1].v += cell.v; + } + } + // if the browser name matches the user's browser then style it + if (cell.p && cell.p.className) { + // prefix the browser name with a line separator (\u2028) because it's not rendered + // (IE may render a negligible space in the tooltip of browser names truncated with ellipsis) + cell.f = uaToken + cell.f; + // poll until the chart elements exist and are styled + poll(function() { return !addChartStyle(); }, 0.01); + } + }); + }); + + // adjust captions and chart dimensions + if (chart == 'Bar') { + // use minHeight to avoid sizing issues when there is only 1 bar + height = max(minHeight, top + (rowCount * cellHeight)); + // compute left by adding the longest approximate vAxis text width and + // a right pad of 10px + left = (maxChars * (fontSize / 1.6)) + 10; + // get percentage of width left after subtracting the chart's left + // coordinate and room for the ops/sec number + areaWidth = (100 - (((left + 50) / width) * 100)) + '%'; + } + else { + // swap captions (the browser list caption is blank to conserve space) + vTitle = [hTitle, hTitle = vTitle][0]; + height = minHeight; + + if (chart == 'Pie') { + legend = 'right'; + title = 'Total operations per second by browser (higher is better)'; + } + else { + hTitleHeight = 28; + // compute left by getting the sum of the horizontal space wanted + // for the vAxis title's width, the approximate vAxis text width, and + // the 13px gap between the chart and the right side of the vAxis text + left = vTitleWidth + (formatNumber(maxOps).length * (fontSize / 1.6)) + 13; + // compute cell width by adding the longest approximate hAxis text + // width and wiggle room of 26px + cellWidth = (maxChars * (fontSize / 2)) + 26; + // use minWidth to avoid clipping the key + width = max(minWidth, left + (rowCount * cellWidth)); + } + } + // get percentage of height left after subtracting the vertical space wanted + // for the hAxis title's height, text size, the chart's top coordinate, + // and the 8px gap between the chart and the top of the hAxis text + areaHeight = (100 - (((hTitleHeight + fontSize + top + 8) / height) * 100)) + '%'; + // make chart type recognizable + chart += 'Chart'; + } + + if (rowCount && visualization[chart]) { + new visualization[chart](cont).draw(data, { + 'colors': ui.browserscope.colors, + 'fontSize': fontSize, + 'is3D': true, + 'legend': legend, + 'height': height, + 'title': title, + 'width': width, + 'chartArea': { 'height': areaHeight, 'left': left, 'top': top, 'width': areaWidth }, + 'hAxis': { 'baseline': 0, 'title': hTitle }, + 'vAxis': { 'baseline': 0, 'title': vTitle } + }); + } else { + setMessage(me.texts.empty); + } + } + } + + /*--------------------------------------------------------------------------*/ + + // expose + ui.browserscope = { + + /** + * Your Browserscope API key. + * + * @memberOf ui.browserscope + * @type String + */ + 'key': '', + + /** + * A flag to indicate if posting is enabled or disabled. + * + * @memberOf ui.browserscope + * @type Boolean + */ + 'postable': true, + + /** + * The selector of the element to contain the entire Browserscope UI. + * + * @memberOf ui.browserscope + * @type String + */ + 'selector': '', + + /** + * The class name used to style the user's browser name when it appears + * in charts. + * + * @memberOf ui.browserscope + * @type String + */ + 'uaClass': 'rt-ua-cur', + + /** + * Object containing various timings settings. + * + * @memberOf ui.browserscope + * @type Object + */ + 'timings': { + + /** + * The delay between removing abandoned script and iframe elements (secs). + * + * @memberOf ui.browserscope.timings + * @type Number + */ + 'cleanup': 10, + + /** + * The delay before refreshing the cumulative results after posting (secs). + * + * @memberOf ui.browserscope.timings + * @type Number + */ + 'refresh': 3, + + /** + * The delay between load attempts (secs). + * + * @memberOf ui.browserscope.timings + * @type Number + */ + 'retry': 5, + + /** + * The time to wait for a request to finish (secs). + * + * @memberOf ui.browserscope.timings + * @type Number + */ + 'timeout': 10 + }, + + /** + * Object containing various text messages. + * + * @memberOf ui.browserscope + * @type Object + */ + 'texts': { + + /** + * The text shown when their is no recorded data available to report. + * + * @memberOf ui.browserscope.texts + * @type String + */ + 'empty': 'No data available', + + /** + * The text shown when the cumulative results data cannot be retrieved. + * + * @memberOf ui.browserscope.texts + * @type String + */ + 'error': 'The get/post request has failed :(', + + /** + * The text shown while waiting for the cumulative results data to load. + * + * @memberOf ui.browserscope.texts + * @type String + */ + 'loading': 'Loading cumulative results data…', + + /** + * The text shown while posting the results snapshot to Browserscope. + * + * @memberOf ui.browserscope.texts + * @type String + */ + 'post': 'Posting results snapshot…', + + /** + * The text shown while benchmarks are running. + * + * @memberOf ui.browserscope.texts + * @type String + */ + 'wait': 'Benchmarks running. Please wait…' + }, + + // loads cumulative results table + 'load': load, + + // posts benchmark snapshot to Browserscope + 'post': post, + + // purges the Browserscope response cache + 'purge': purge, + + // renders cumulative results table + 'render': render + }; + + /*--------------------------------------------------------------------------*/ + + addListener(window, 'load', function() { + var me = ui.browserscope, + key = me.key, + placeholder = key && query(me.selector)[0]; + + // create results html + if (placeholder) { + setHTML(placeholder, + '<h1 id=bs-logo><a href=//www.browserscope.org/user/tests/table/#{key}>' + + '<span>Browserscope</span></a></h1>' + + '<div class=bs-rt><div id=bs-chart></div></div>', + { 'key': key }); + + // the element the charts are inserted into + me.container = query('#bs-chart')[0]; + + // Browserscope's UA div is inserted before an element with the id of "bs-ua-script" + loadScript('//www.browserscope.org/ua?o=js', me.container).id = 'bs-ua-script'; + + // the "autoload" string can be created with + // http://code.google.com/apis/loader/autoloader-wizard.html + loadScript('//www.google.com/jsapi?autoload=' + encodeURIComponent('{' + + 'modules:[{' + + 'name:"visualization",' + + 'version:1,' + + 'packages:["corechart","table"],' + + 'callback:ui.browserscope.load' + + '}]' + + '}')); + + // init garbage collector + cleanup(); + } + }); + + // hide the chart while benchmarks are running + ui.on('start', function() { + setMessage(ui.browserscope.texts.wait); + }) + .on('abort', function() { + ui.browserscope.render({ 'force': true }); + }); + +}(this, document)); diff --git a/web/src/vendor/benchmark/test/benchmark.air/.actionScriptProperties b/web/src/vendor/benchmark/test/benchmark.air/.actionScriptProperties new file mode 100644 index 00000000..53a44ecd --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/.actionScriptProperties @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<actionScriptProperties analytics="false" mainApplicationPath="air.mxml" projectUUID="f1d53a64-add9-48c3-9e81-bd3b388963e7" version="10"> + <compiler additionalCompilerArguments="-locale en_US" autoRSLOrdering="true" copyDependentFiles="true" fteInMXComponents="false" generateAccessible="true" htmlExpressInstall="true" htmlGenerate="false" htmlHistoryManagement="false" htmlPlayerVersionCheck="true" includeNetmonSwc="false" outputFolderPath="bin-debug" removeUnusedRSL="true" sourceFolderPath="src" strict="true" targetPlayerVersion="0.0.0" useApolloConfig="true" useDebugRSLSwfs="true" verifyDigests="true" warn="true"> + <compilerSourcePath/> + <libraryPath defaultLinkType="0"/> + <sourceAttachmentPath/> + </compiler> + <applications> + <application path="air.mxml"> + <airExcludes/> + </application> + </applications> + <modules/> + <buildCSSFiles/> + <flashCatalyst validateFlashCatalystCompatibility="false"/> + <buildTargets> + <buildTarget buildTargetName="default"> + <airSettings airCertificatePath="" airTimestamp="true" version="1"> + <airExcludes/> + </airSettings> + <actionScriptSettings version="1"/> + </buildTarget> + </buildTargets> +</actionScriptProperties> diff --git a/web/src/vendor/benchmark/test/benchmark.air/.flexProperties b/web/src/vendor/benchmark/test/benchmark.air/.flexProperties new file mode 100644 index 00000000..f2072112 --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/.flexProperties @@ -0,0 +1,2 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<flexProperties enableServiceManager="false" flexServerFeatures="0" flexServerType="0" toolCompile="true" useServerFlexSDK="false" version="2"/> diff --git a/web/src/vendor/benchmark/test/benchmark.air/.project b/web/src/vendor/benchmark/test/benchmark.air/.project new file mode 100644 index 00000000..98fe0436 --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/.project @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>benchmark.air</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>com.adobe.flexbuilder.project.flexbuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.adobe.flexbuilder.project.apollobuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>com.adobe.flexbuilder.project.apollonature</nature> + <nature>com.adobe.flexbuilder.project.flexnature</nature> + <nature>com.adobe.flexbuilder.project.actionscriptnature</nature> + </natures> +</projectDescription> diff --git a/web/src/vendor/benchmark/test/benchmark.air/README.md b/web/src/vendor/benchmark/test/benchmark.air/README.md new file mode 100644 index 00000000..a304b6fa --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/README.md @@ -0,0 +1,6 @@ +# Instructions + +Before importing the Flash Builder project please perform the following steps: + + 1. Copy/paste `benchmark.js` into the `src` folder. + 2. Copy/paste `AIRIntrospector.js` from some place like `C:\Program Files\Adobe\Adobe Flash Builder 4.5\sdks\4.5.0\frameworks\libs\air\AIRIntrospector.js` into the `src` folder. diff --git a/web/src/vendor/benchmark/test/benchmark.air/bin-debug/air.swf b/web/src/vendor/benchmark/test/benchmark.air/bin-debug/air.swf Binary files differnew file mode 100644 index 00000000..53399542 --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/bin-debug/air.swf diff --git a/web/src/vendor/benchmark/test/benchmark.air/src/air-app.xml b/web/src/vendor/benchmark/test/benchmark.air/src/air-app.xml new file mode 100644 index 00000000..0ef97076 --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/src/air-app.xml @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="utf-8" standalone="no"?> +<application xmlns="http://ns.adobe.com/air/application/2.6"> + <id>air</id> + <filename>air</filename> + <name>air</name> + <versionNumber>0.0.0</versionNumber> + <initialWindow> + <content>index.html</content> + <resizable>true</resizable> + <width>320</width> + <height>240</height> + <autoOrients>false</autoOrients> + <fullScreen>false</fullScreen> + <visible>true</visible> + </initialWindow> +</application> diff --git a/web/src/vendor/benchmark/test/benchmark.air/src/air.mxml b/web/src/vendor/benchmark/test/benchmark.air/src/air.mxml new file mode 100644 index 00000000..c2c46603 --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/src/air.mxml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009" + xmlns:s="library://ns.adobe.com/flex/spark" + xmlns:mx="library://ns.adobe.com/flex/mx"> + <fx:Declarations> + </fx:Declarations> +</s:WindowedApplication> diff --git a/web/src/vendor/benchmark/test/benchmark.air/src/index.html b/web/src/vendor/benchmark/test/benchmark.air/src/index.html new file mode 100644 index 00000000..1a1eb196 --- /dev/null +++ b/web/src/vendor/benchmark/test/benchmark.air/src/index.html @@ -0,0 +1,37 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Benchmark.js Adobe AIR Test Suite</title> + <script src="AIRIntrospector.js"></script> + <script> + var console = air.Introspector.Console; + </script> + <script src="benchmark.js"></script> + </head> + <body> + <script> + (function() { + var suite = new Benchmark.Suite; + + // add tests + suite.add('RegExp#test', function() { + /o/.test('Hello World!'); + }) + .add('String#indexOf', function() { + 'Hello World!'.indexOf('o') > -1; + }) + // add listeners + .on('cycle', function(event) { + console.log(event.target); + }) + .on('complete', function() { + console.log('Fastest is ' + this.filter('fastest').pluck('name')); + }) + // don't run async to avoid JavaScript security errors + // http://help.adobe.com/en_US/AIR/1.5/devappshtml/WS5b3ccc516d4fbf351e63e3d118666ade46-7f0e.html + .run({ 'async': false }); + }()); + </script> + </body> +</html> diff --git a/web/src/vendor/benchmark/test/index.html b/web/src/vendor/benchmark/test/index.html new file mode 100644 index 00000000..9762fb69 --- /dev/null +++ b/web/src/vendor/benchmark/test/index.html @@ -0,0 +1,85 @@ +<!doctype html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <title>Benchmark.js Test Suite</title> + <link rel="stylesheet" href="../vendor/qunit/qunit/qunit.css"> + <style> + applet { + position: absolute; + left: -9999em; + } + </style> + </head> + <body> + <div id="qunit"></div> + <script src="../benchmark.js"></script> + <script src="../vendor/platform.js/platform.js"></script> + <script> + (function() { + var hasOwnProperty = function hasOwnProperty(key) { + var parent = (this.constructor || Object).prototype; + return key in this && !(key in parent && this[key] === parent[key]); + }; + if (typeof {}.hasOwnProperty != 'function') { + // redefine for Safari 2, else use the less accurate fallback for others + if ({}.__proto__ == Object.prototype) { + hasOwnProperty = function hasOwnProperty(key) { + var result; + this.__proto__ = [this.__proto__, this.__proto__ = null, result = key in this][0]; + return result; + }; + } + Object.prototype.hasOwnProperty = hasOwnProperty; + } + }()); + + // load the nanosecond timer + if (!/[?&]nojava=true(?:&|$)/.test(location.search)) { + document.write('<applet code="nano" archive="../nano.jar"></applet>'); + } + + // avoid syntax errors for `QUnit.throws` in older Firefoxes + document.write(platform.name == 'Firefox' && /^1\b/.test(platform.version) + ? '<script src="../vendor/qunit/qunit/qunit-1.8.0.js"><\/script>' + : '<script src="../vendor/qunit/qunit/qunit.js"><\/script>' + ); + </script> + <script> + // load test.js if not using require.js + document.write(/[?&]norequire=true(?:&|$)/.test(location.search) + ? '<script src="test.js"><\/script>' + : '<script src="../vendor/requirejs/require.js"><\/script>' + ); + </script> + <script> + // load Benchmark as a module + var Benchmark2; + + window.require && require({ + 'baseUrl': '../vendor/requirejs/', + 'urlArgs': 't=' + (+new Date), + 'paths': { + 'benchmark': '../../benchmark', + 'platform': '../platform.js/platform' + } + }, + ['benchmark', 'platform'], function(Benchmark, platform) { + Benchmark2 = Benchmark; + Benchmark2.platform = platform; + require(['test.js']); + }); + + // set a more readable browser name + window.onload = function() { + var timeoutId = setInterval(function() { + var ua = document.getElementById('qunit-userAgent'); + if (ua) { + ua.innerHTML = platform; + clearInterval(timeoutId); + } + }, 15); + }; + </script> + </body> +</html> diff --git a/web/src/vendor/benchmark/test/run-test.sh b/web/src/vendor/benchmark/test/run-test.sh new file mode 100755 index 00000000..43424e43 --- /dev/null +++ b/web/src/vendor/benchmark/test/run-test.sh @@ -0,0 +1,9 @@ +cd "$(dirname "$0")" +for cmd in rhino ringo narwhal node; do + echo "" + echo "Testing in $cmd..." + $cmd test.js +done +echo "" +echo "Testing in a browser..." +open index.html diff --git a/web/src/vendor/benchmark/test/test.js b/web/src/vendor/benchmark/test/test.js new file mode 100644 index 00000000..d6944940 --- /dev/null +++ b/web/src/vendor/benchmark/test/test.js @@ -0,0 +1,2074 @@ +;(function(window, undefined) { + 'use strict'; + + /** Use a single load function */ + var load = typeof require == 'function' ? require : window.load; + + /** The `platform` object to check */ + var platform = + window.platform || + load('../vendor/platform.js/platform.js') || + window.platform; + + /** The unit testing framework */ + var QUnit = + window.QUnit || ( + window.setTimeout || (window.addEventListener = window.setTimeout = / /), + window.QUnit = load('../vendor/qunit/qunit/qunit' + (platform.name == 'Narwhal' ? '-1.8.0' : '') + '.js') || window.QUnit, + load('../vendor/qunit-clib/qunit-clib.js'), + (window.addEventListener || 0).test && delete window.addEventListener, + window.QUnit + ); + + /** The `Benchmark` constructor to test */ + var Benchmark = + window.Benchmark || ( + Benchmark = load('../benchmark.js') || window.Benchmark, + Benchmark.Benchmark || Benchmark + ); + + /** API shortcut */ + var forOwn = Benchmark.forOwn; + + /** Used to get property descriptors */ + var getDescriptor = Object.getOwnPropertyDescriptor; + + /** Used to set property descriptors */ + var setDescriptor = Object.defineProperty; + + /** Shortcut used to convert array-like objects to arrays */ + var slice = [].slice; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** Used to check problem JScript properties (a.k.a. the [[DontEnum]] bug) */ + var shadowed = { + 'constructor': 1, + 'hasOwnProperty': 2, + 'isPrototypeOf': 3, + 'propertyIsEnumerable': 4, + 'toLocaleString': 5, + 'toString': 6, + 'valueOf': 7 + }; + + /** Used to flag environments/features */ + var support = { + 'descriptors': !!function() { + try { + var o = {}; + return (setDescriptor(o, o, o), 'value' in getDescriptor(o, o)); + } catch(e) { } + }() + }; + + /*--------------------------------------------------------------------------*/ + + /** + * Skips a given number of tests with a passing result. + * + * @private + * @param {Number} [count=1] The number of tests to skip. + */ + function skipTest(count) { + count || (count = 1); + while (count--) { + ok(true, 'test skipped'); + } + } + + /*--------------------------------------------------------------------------*/ + + // init Benchmark.options.minTime + Benchmark(function() { throw 0; }).run(); + + // set a shorter max time + Benchmark.options.maxTime = Benchmark.options.minTime * 5; + + // explicitly call `QUnit.module()` instead of `module()` + // in case we are in a CLI environment + QUnit.module('Benchmark'); + + (function() { + test('has the default `Benchmark.platform` value', function() { + if (window.document) { + equal(String(Benchmark.platform), navigator.userAgent); + } else { + skipTest(1) + } + }); + + test('supports loading Benchmark.js as a module', function() { + if (window.document && window.require) { + equal((Benchmark2 || {}).version, Benchmark.version); + } else { + skipTest(1) + } + }); + + test('supports loading Platform.js as a module', function() { + if (window.document && window.require) { + var platform = (Benchmark2 || {}).platform || {}; + equal(typeof platform.name, 'string'); + } else { + skipTest(1) + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark constructor'); + + (function() { + test('creates a new instance when called without the `new` operator', function() { + ok(Benchmark() instanceof Benchmark); + }); + + test('supports passing an options object', function() { + var bench = Benchmark({ 'name': 'foo', 'fn': function() { } }); + ok(bench.fn && bench.name == 'foo'); + }); + + test('supports passing a "name" and "fn" argument', function() { + var bench = Benchmark('foo', function() { }); + ok(bench.fn && bench.name == 'foo'); + }); + + test('supports passing a "name" argument and an options object', function() { + var bench = Benchmark('foo', { 'fn': function() { } }); + ok(bench.fn && bench.name == 'foo'); + }); + + test('supports passing a "name" argument and an options object', function() { + var bench = Benchmark('foo', function() { }, { 'id': 'bar' }); + ok(bench.fn && bench.name == 'foo' && bench.id == 'bar'); + }); + + test('supports passing an empy string for the "fn" options property', function() { + var bench = Benchmark({ 'fn': '' }).run(); + ok(!bench.error); + }); + + test('detects dead code', function() { + var bench = Benchmark(function() { }).run(); + ok(/setup\(\)/.test(bench.compiled) ? !bench.error : bench.error); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark compilation'); + + (function() { + test('compiles using the default `Function#toString`', function() { + var bench = Benchmark({ + 'setup': function() { var a = 1; }, + 'fn': function() { throw a; }, + 'teardown': function() { a = 2; } + }).run(); + + var compiled = bench.compiled; + if (/setup\(\)/.test(compiled)) { + skipTest(); + } + else { + ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled)); + } + }); + + test('compiles using a custom "toString" method', function() { + var bench = Benchmark({ + 'setup': function() { }, + 'fn': function() { }, + 'teardown': function() { } + }); + + bench.setup.toString = function() { return 'var a = 1;' }; + bench.fn.toString = function() { return 'throw a;' }; + bench.teardown.toString = function() { return 'a = 2;' }; + bench.run(); + + var compiled = bench.compiled; + if (/setup\(\)/.test(compiled)) { + skipTest(); + } + else { + ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled)); + } + }); + + test('compiles using a string value', function() { + var bench = Benchmark({ + 'setup': 'var a = 1;', + 'fn': 'throw a;', + 'teardown': 'a = 2;' + }).run(); + + var compiled = bench.compiled; + if (/setup\(\)/.test(compiled)) { + skipTest(); + } + else { + ok(/var a\s*=\s*1/.test(compiled) && /throw a/.test(compiled) && /a\s*=\s*2/.test(compiled)); + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark test binding'); + + (function() { + var count = 0; + + var tests = { + 'inlined "setup", "fn", and "teardown"': ( + 'if(/ops/.test(this))this._fn=true;' + ), + 'called "fn" and inlined "setup"/"teardown" reached by error': function() { + count++; + if (/ops/.test(this)) { + this._fn = true; + } + }, + 'called "fn" and inlined "setup"/"teardown" reached by `return` statement': function() { + if (/ops/.test(this)) { + this._fn = true; + } + return; + } + }; + + forOwn(tests, function(fn, title) { + test('has correct binding for ' + title, function() { + var bench = Benchmark({ + 'setup': 'if(/ops/.test(this))this._setup=true;', + 'fn': fn, + 'teardown': 'if(/ops/.test(this))this._teardown=true;', + 'onCycle': function() { this.abort(); } + }).run(); + + var compiled = bench.compiled; + if (/setup\(\)/.test(compiled)) { + skipTest(3); + } + else { + ok(bench._setup, 'correct binding for "setup"'); + ok(bench._fn, 'correct binding for "fn"'); + ok(bench._teardown, 'correct binding for "teardown"'); + } + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.deepClone'); + + (function() { + function createCircularObject() { + var result = { + 'foo': { 'b': { 'foo': { 'c': { } } } }, + 'bar': { } + }; + + result.foo.b.foo.c.foo = result; + result.bar.b = result.foo.b; + return result; + } + + function Klass() { + this.a = 1; + } + + Klass.prototype = { 'b': 1 }; + + var notCloneable = { + 'an arguments object': arguments, + 'an element': window.document && document.body, + 'a function': Klass, + 'a Klass instance': new Klass + }; + + var objects = { + 'an array': ['a', 'b', 'c', ''], + 'an array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 }, + 'boolean': false, + 'boolean object': Object(false), + 'an object': { 'a': 0, 'b': 1, 'c': 3 }, + 'an object with object values': { 'a': /a/, 'b': ['B'], 'c': { 'C': 1 } }, + 'null': null, + 'a number': 3, + 'a number object': Object(3), + 'a regexp': /x/gim, + 'a string': 'x', + 'a string object': Object('x'), + 'undefined': undefined + }; + + objects['an array'].length = 5; + + forOwn(objects, function(object, key) { + test('clones ' + key + ' correctly', function() { + var kind = toString.call(object), + clone = Benchmark.deepClone(object); + + if (object == null) { + equal(clone, object); + } else { + deepEqual(clone.valueOf(), object.valueOf()); + } + if (object === Object(object)) { + ok(clone !== object); + } else { + skipTest(); + } + }); + }); + + forOwn(notCloneable, function(object, key) { + test('does not clone ' + key, function() { + ok(Benchmark.deepClone(object) === object); + }); + }); + + test('clones using Klass#deepClone', function() { + var object = new Klass; + Klass.prototype.deepClone = function() { return new Klass; }; + + var clone = Benchmark.deepClone(object); + ok(clone !== object && clone instanceof Klass); + + delete Klass.prototype.clone; + }); + + test('clones problem JScript properties', function() { + var clone = Benchmark.deepClone(shadowed); + deepEqual(clone, shadowed); + }); + + test('clones string object with custom property', function() { + var object = new String('x'); + object.x = 1; + + var clone = Benchmark.deepClone(object); + ok(clone == 'x' && typeof clone == 'object' && clone.x === 1 && toString.call(clone) == '[object String]'); + }); + + test('clones objects with circular references', function() { + var object = createCircularObject(), + clone = Benchmark.deepClone(object); + + ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object); + }); + + test('clones non-extensible objects with circular references', function() { + if (Object.preventExtensions) { + var object = Object.preventExtensions(createCircularObject()); + Object.preventExtensions(object.bar.b); + + var clone = Benchmark.deepClone(object); + ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object); + } else { + skipTest(1) + } + }); + + test('clones sealed objects with circular references', function() { + if (Object.seal) { + var object = Object.seal(createCircularObject()); + Object.seal(object.bar.b); + + var clone = Benchmark.deepClone(object); + ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object); + } else { + skipTest(1) + } + }); + + test('clones frozen objects with circular references', function() { + if (Object.freeze) { + var object = Object.freeze(createCircularObject()); + Object.freeze(object.bar.b); + + var clone = Benchmark.deepClone(object); + ok(clone.bar.b === clone.foo.b && clone === clone.foo.b.foo.c.foo && clone !== object); + } else { + skipTest(1) + } + }); + + test('clones objects with custom descriptors and circular references', function() { + var accessor, + descriptor; + + if (support.descriptors) { + var object = setDescriptor({}, 'foo', { + 'configurable': true, + 'value': setDescriptor({}, 'b', { + 'writable': true, + 'value': setDescriptor({}, 'foo', { + 'get': function() { return accessor; }, + 'set': function(value) { accessor = value; } + }) + }) + }); + + setDescriptor(object, 'bar', { 'value': {} }); + object.foo.b.foo = { 'c': object }; + object.bar.b = object.foo.b; + + var clone = Benchmark.deepClone(object); + ok(clone !== object && + clone.bar.b === clone.foo.b && + clone !== clone.foo.b.foo.c.foo && + (descriptor = getDescriptor(clone, 'foo')) && + descriptor.configurable && !(descriptor.enumerable && descriptor.writable) && + (descriptor = getDescriptor(clone.foo, 'b')) && + descriptor.writable && !(descriptor.configurable && descriptor.enumerable) && + (descriptor = getDescriptor(clone.foo.b, 'foo')) && + descriptor.get && descriptor.set && + (descriptor = getDescriptor(clone.foo.b, 'foo')) && + !(descriptor.configurable && descriptor.enumerable && descriptor.writable) && + (descriptor = getDescriptor(clone, 'bar')) && + !(descriptor.configurable && descriptor.enumerable && descriptor.writable)); + } + else { + skipTest(1) + } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.each'); + + (function() { + var xpathResult; + + var objects = { + 'array': ['a', 'b', 'c', ''], + 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 }, + 'xpath snapshot': null + }; + + if (window.document && document.evaluate) { + xpathResult = [document.documentElement, document.getElementsByTagName('head')[0], document.body]; + objects['xpath snapshot'] = document.evaluate('//*[self::html or self::head or self::body]', document, null, 7, null); + } + + objects.array.length = 5; + + forOwn(objects, function(object, key) { + test('passes the correct arguments when passing an ' + key, function() { + if (object) { + var args + Benchmark.each(object, function() { + args || (args = slice.call(arguments)); + }); + + if (key == 'xpath snapshot') { + ok(args[0] === xpathResult[0]); + } else { + equal(args[0], 'a'); + } + equal(args[1], 0); + ok(args[2] === object); + } + else { + skipTest(3); + } + }); + + test('returns the passed object when passing an ' + key, function() { + if (object) { + var actual = Benchmark.each(object, function() { }); + ok(actual === object); + } + else { + skipTest(); + } + }); + + test('iterates over all indexes when passing an ' + key, function() { + if (object) { + var values = []; + Benchmark.each(object, function(value) { + values.push(value); + }); + + deepEqual(values, key == 'xpath snapshot' ? xpathResult : ['a', 'b', 'c', '']); + } + else { + skipTest(); + } + }); + + test('exits early when returning `false` when passing an ' + key, function() { + if (object) { + var values = []; + Benchmark.each(object, function(value) { + values.push(value); + return values.length < 2; + }); + + deepEqual(values, key == 'xpath snapshot' ? xpathResult.slice(0, 2) : ['a', 'b']); + } + else { + skipTest(); + } + }); + }); + + test('passes the third callback argument as an object', function() { + var thirdArg; + Benchmark.each('hello', function(value, index, object) { + thirdArg = object; + }); + + ok(thirdArg && typeof thirdArg == 'object'); + }); + + test('iterates over strings by index', function() { + var values = []; + Benchmark.each('hello', function(value) { + values.push(value) + }); + + deepEqual(values, ['h', 'e', 'l', 'l', 'o']); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.extend'); + + (function() { + test('allows no source argument', function() { + var object = {}; + equal(Benchmark.extend(object), object); + }); + + test('allows a single source argument', function() { + var source = { 'x': 1, 'y': 1 }, + actual = Benchmark.extend({}, source); + + deepEqual(Benchmark.extend({}, source), { 'x': 1, 'y': 1 }); + }); + + test('allows multiple source arguments', function() { + var source1 = { 'x': 1, 'y': 1 }, + source2 = { 'y': 2, 'z': 2 }, + actual = Benchmark.extend({}, source1, source2); + + deepEqual(actual, { 'x': 1, 'y': 2, 'z': 2 }); + }); + + test('will add inherited source properties', function() { + function Source() { } + Source.prototype.x = 1; + deepEqual(Benchmark.extend({}, new Source), { 'x': 1 }); + }); + + test('will add problem JScript properties', function() { + deepEqual(Benchmark.extend({}, shadowed), shadowed); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.filter'); + + (function() { + var objects = { + 'array': ['a', 'b', 'c', ''], + 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 } + }; + + objects.array.length = 5; + + forOwn(objects, function(object, key) { + test('passes the correct arguments when passing an ' + key, function() { + var args; + Benchmark.filter(object, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, ['a', 0, object]); + }); + + test('produces the correct result when passing an ' + key, function() { + var actual = Benchmark.filter(object, function(value, index) { + return index > 0; + }); + + deepEqual(actual, ['b', 'c', '']); + }); + + test('iterates over sparse ' + key + 's correctly', function() { + var actual = Benchmark.filter(object, function(value) { + return value === undefined; + }); + + deepEqual(actual, []); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.forOwn'); + + (function() { + function fn() { + // no-op + } + + function KlassA() { + this.a = 1; + this.b = 2; + this.c = 3; + } + + function KlassB() { + this.a = 1; + this.constructor = 2; + this.hasOwnProperty = 3; + this.isPrototypeOf = 4; + this.propertyIsEnumerable = 5; + this.toLocaleString = 6; + this.toString = 7; + this.valueOf = 8; + } + + function KlassC() { + // no-op + } + + fn.a = 1; + fn.b = 2; + fn.c = 3; + + KlassC.prototype.a = 1; + KlassC.prototype.b = 2; + KlassC.prototype.c = 3; + + var objects = { + 'an arguments object': arguments, + 'a function': fn, + 'an object': new KlassA, + 'an object shadowing properties on Object.prototype': new KlassB, + 'a prototype object': KlassC.prototype, + 'a string': 'abc' + }; + + forOwn(objects, function(object, key) { + test('passes the correct arguments when passing ' + key, function() { + var args; + Benchmark.forOwn(object, function() { + args || (args = slice.call(arguments)); + }); + + equal(typeof args[0], key == 'a string' ? 'string' : 'number'); + equal(typeof args[1], 'string'); + equal(args[2] && typeof args[2], key == 'a function' ? 'function' : 'object'); + }); + + test('returns the passed object when passing ' + key, function() { + var actual = Benchmark.forOwn(object, function() { }); + deepEqual(actual, object); + }); + + test('iterates over own properties when passing ' + key, function() { + var values = []; + Benchmark.forOwn(object, function(value) { + values.push(value); + }); + + if (object instanceof KlassB) { + deepEqual(values.sort(), [1, 2, 3, 4, 5, 6, 7, 8]); + } else if (key == 'a string') { + deepEqual(values, ['a', 'b', 'c']); + } else { + deepEqual(values.sort(), [1, 2, 3]); + } + }); + + test('exits early when returning `false` when passing ' + key, function() { + var values = []; + Benchmark.forOwn(object, function(value) { + values.push(value); + return false; + }); + + equal(values.length, 1); + }); + + if (object instanceof KlassB) { + test('exits correctly when transitioning to the JScript [[DontEnum]] fix', function() { + var values = []; + Benchmark.forOwn(object, function(value) { + values.push(value); + return values.length < 2; + }); + + equal(values.length, 2); + }); + } + }); + }(1, 2, 3)); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.formatNumber'); + + (function() { + test('formats a million correctly', function() { + equal(Benchmark.formatNumber(1e6), '1,000,000'); + }); + + test('formats less than 100 correctly', function() { + equal(Benchmark.formatNumber(23), '23'); + }); + + test('formats numbers with decimal values correctly', function() { + equal(Benchmark.formatNumber(1234.56), '1,234.56'); + }); + + test('formats negative numbers correctly', function() { + equal(Benchmark.formatNumber(-1234.56), '-1,234.56'); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.hasKey'); + + (function() { + test('returns `true` for own properties', function() { + var object = { 'x': 1 }; + equal(Benchmark.hasKey(object, 'x'), true); + }); + + test('returns `false` for inherited properties', function() { + equal(Benchmark.hasKey({}, 'toString'), false); + }); + + test('doesn\'t use an object\'s `hasOwnProperty` method', function() { + var object = { 'hasOwnProperty': function() { return true; } }; + equal(Benchmark.hasKey(object, 'x'), false); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.indexOf'); + + (function() { + var objects = { + 'array': ['a', 'b', 'c', ''], + 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 } + }; + + objects.array.length = 5; + + forOwn(objects, function(object, key) { + test('produces the correct result when passing an ' + key, function() { + equal(Benchmark.indexOf(object, 'b'), 1); + }); + + test('matches values by strict equality when passing an ' + key, function() { + equal(Benchmark.indexOf(object, new String('b')), -1); + }); + + test('iterates over sparse ' + key + 's correctly', function() { + equal(Benchmark.indexOf(object, undefined), -1); + }); + }); + + test('searches from the given `fromIndex`', function() { + var array = ['a', 'b', 'c', 'a']; + equal(Benchmark.indexOf(array, 'a', 1), 3); + }); + + test('handles extreme negative `fromIndex` values correctly', function() { + var array = ['a']; + array['-1'] = 'z'; + equal(Benchmark.indexOf(array, 'z', -2), -1); + }); + + test('handles extreme positive `fromIndex` values correctly', function() { + var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 2 }; + equal(Benchmark.indexOf(object, 'c', 2), -1); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.interpolate'); + + (function() { + test('replaces tokens correctly', function() { + var actual = Benchmark.interpolate('#{greeting} #{location}.', { + 'greeting': 'Hello', + 'location': 'world' + }); + + equal(actual, 'Hello world.'); + }); + + test('ignores inherited object properties', function() { + var actual = Benchmark.interpolate('x#{toString}', {}); + equal(actual, 'x#{toString}'); + }); + + test('allows for no template object', function() { + var actual = Benchmark.interpolate('x'); + equal(actual, 'x'); + }); + + test('replaces duplicate tokens', function() { + var actual = Benchmark.interpolate('#{x}#{x}#{x}', { 'x': 'a' }); + equal(actual, 'aaa'); + }); + + test('handles keys containing RegExp special characters', function() { + var actual = Benchmark.interpolate('#{.*+?^=!:${}()|[]\\/}', { '.*+?^=!:${}()|[]\\/': 'x' }); + equal(actual, 'x'); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.invoke'); + + (function() { + var objects = { + 'array': ['a', ['b'], 'c', null], + 'array-like-object': { '0': 'a', '1': ['b'], '2': 'c', '3': null, 'length': 5 } + }; + + objects.array.length = 5; + + forOwn(objects, function(object, key) { + test('produces the correct result when passing an ' + key, function() { + var actual = Benchmark.invoke(object, 'concat'); + deepEqual(actual, ['a', ['b'], 'c', undefined, undefined]); + equal('4' in actual, false); + }); + + test('passes the correct arguments to the invoked method when passing an ' + key, function() { + var actual = Benchmark.invoke(object, 'concat', 'x', 'y', 'z'); + deepEqual(actual, ['axyz', ['b', 'x', 'y', 'z'], 'cxyz', undefined, undefined]); + equal('4' in actual, false); + }); + + test('handles options object with callbacks correctly when passing an ' + key, function() { + function callback() { + callbacks.push(slice.call(arguments)); + } + + var callbacks = []; + var actual = Benchmark.invoke(object, { + 'name': 'concat', + 'args': ['x', 'y', 'z'], + 'onStart': callback, + 'onCycle': callback, + 'onComplete': callback + }); + + deepEqual(actual, ['axyz', ['b', 'x', 'y', 'z'], 'cxyz', undefined, undefined]); + equal('4' in actual, false); + + equal(callbacks[0].length, 1); + equal(callbacks[0][0].target, 'a'); + deepEqual(callbacks[0][0].currentTarget, object); + equal(callbacks[0][0].type, 'start'); + equal(callbacks[1][0].type, 'cycle'); + equal(callbacks[5][0].type, 'complete'); + }); + + test('supports queuing when passing an ' + key, function() { + var lengths = []; + var actual = Benchmark.invoke(object, { + 'name': 'concat', + 'queued': true, + 'args': 'x', + 'onCycle': function() { + lengths.push(object.length); + } + }); + + deepEqual(lengths, [5, 4, 3, 2]); + deepEqual(actual, ['ax', ['b', 'x'], 'cx', undefined, undefined]); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.join'); + + (function() { + var objects = { + 'array': ['a', 'b', ''], + 'array-like-object': { '0': 'a', '1': 'b', '2': '', 'length': 4 }, + 'object': { 'a': '0', 'b': '1', '': '2' } + }; + + objects.array.length = 4; + + forOwn(objects, function(object, key) { + test('joins correctly using the default separator when passing an ' + key, function() { + equal(Benchmark.join(object), key == 'object' ? 'a: 0,b: 1,: 2' : 'a,b,'); + }); + + test('joins correctly using a custom separator when passing an ' + key, function() { + equal(Benchmark.join(object, '+', '@'), key == 'object' ? 'a@0+b@1+@2' : 'a+b+'); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.map'); + + (function() { + var objects = { + 'array': ['a', 'b', 'c', ''], + 'array-like-object': { '0': 'a', '1': 'b', '2': 'c', '3': '', 'length': 5 } + }; + + objects.array.length = 5; + + forOwn(objects, function(object, key) { + test('passes the correct arguments when passing an ' + key, function() { + var args; + Benchmark.map(object, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, ['a', 0, object]); + }); + + test('produces the correct result when passing an ' + key, function() { + var actual = Benchmark.map(object, function(value, index) { + return value + index; + }); + + deepEqual(actual, ['a0', 'b1', 'c2', '3', undefined]); + equal('4' in actual, false); + }); + + test('produces an array of the correct length for sparse ' + key + 's', function() { + equal(Benchmark.map(object, function() { }).length, 5); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.pluck'); + + (function() { + var objects = { + 'array': [{ '_': 'a' }, { '_': 'b' }, { '_': 'c' }, null], + 'array-like-object': { '0': { '_': 'a' }, '1': { '_': 'b' }, '2': { '_': 'c' }, '3': null, 'length': 5 } + }; + + objects.array.length = 5; + + forOwn(objects, function(object, key) { + test('produces the correct result when passing an ' + key, function() { + var actual = Benchmark.pluck(object, '_'); + deepEqual(actual, ['a', 'b', 'c', undefined, undefined]); + equal('4' in actual, false); + }); + + test('produces the correct result for non-existent keys when passing an ' + key, function() { + var actual = Benchmark.pluck(object, 'non-existent'); + deepEqual(actual, [undefined, undefined, undefined, undefined, undefined]); + equal('4' in actual, false); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.reduce'); + + (function() { + var objects = { + 'array': ['b', 'c', ''], + 'array-like-object': { '0': 'b', '1': 'c', '2': '', 'length': 4 } + }; + + objects.array.length = 4; + + forOwn(objects, function(object, key) { + test('passes the correct arguments when passing an ' + key, function() { + var args; + Benchmark.reduce(object, function() { + args || (args = slice.call(arguments)); + }, 'a'); + + deepEqual(args, ['a', 'b', 0, object]); + }); + + test('accumulates correctly when passing an ' + key, function() { + var actual = Benchmark.reduce(object, function(string, value) { + return string + value; + }, 'a'); + + equal(actual, 'abc'); + }); + + test('handles arguments with no initial value correctly when passing an ' + key, function() { + var args; + Benchmark.reduce(object, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, ['b', 'c', 1, object]); + }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark#clone'); + + (function() { + var bench = Benchmark(function() { this.count += 0; }).run(); + + test('produces the correct result passing no arguments', function() { + var clone = bench.clone(); + deepEqual(clone, bench); + ok(clone.stats != bench.stats && clone.times != bench.times && clone.options != bench.options); + }); + + test('produces the correct result passing a data object', function() { + var clone = bench.clone({ 'fn': '', 'name': 'foo' }); + ok(clone.fn === '' && clone.options.fn === ''); + ok(clone.name == 'foo' && clone.options.name == 'foo'); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark#run'); + + (function() { + var data = { 'onComplete': 0, 'onCycle': 0, 'onStart': 0 }; + + var bench = Benchmark({ + 'fn': function() { + this.count += 0; + }, + 'onStart': function() { + data.onStart++; + }, + 'onComplete': function() { + data.onComplete++; + } + }) + .run(); + + test('onXYZ callbacks should not be triggered by internal benchmark clones', function() { + equal(data.onStart, 1); + equal(data.onComplete, 1); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + forOwn({ + 'Benchmark': Benchmark, + 'Benchmark.Suite': Benchmark.Suite + }, + function(Constructor, namespace) { + + QUnit.module(namespace + '#emit'); + + (function() { + test('emits passed arguments', function() { + var args, + object = Constructor(); + + object.on('args', function() { args = slice.call(arguments, 1); }); + object.emit('args', 'a', 'b', 'c'); + deepEqual(args, ['a', 'b', 'c']); + }); + + test('emits with no listeners', function() { + var event = Benchmark.Event('empty'), + object = Constructor(); + + object.emit(event); + equal(event.cancelled, false); + }); + + test('emits with an event type of "toString"', function() { + var event = Benchmark.Event('toString'), + object = Constructor(); + + object.emit(event); + equal(event.cancelled, false); + }); + + test('returns the last listeners returned value', function() { + var event = Benchmark.Event('result'), + object = Constructor(); + + object.on('result', function() { return 'x'; }); + object.on('result', function() { return 'y'; }); + equal(object.emit(event), 'y'); + }); + + test('aborts the emitters listener iteration when `event.aborted` is `true`', function() { + var event = Benchmark.Event('aborted'), + object = Constructor(); + + object.on('aborted', function(event) { + event.aborted = true; + return false; + }); + + object.on('aborted', function(event) { + // should not get here + event.aborted = false; + return true; + }); + + equal(object.emit(event), false); + equal(event.aborted, true); + }); + + test('cancels the event if a listener explicitly returns `false`', function() { + var event = Benchmark.Event('cancel'), + object = Constructor(); + + object.on('cancel', function() { return false; }); + object.on('cancel', function() { return true; }); + object.emit(event); + equal(event.cancelled, true); + }); + + test('uses a shallow clone of the listeners when emitting', function() { + var event, + listener2 = function(eventObject) { eventObject.listener2 = true }, + object = Constructor(); + + object.on('shallowclone', function(eventObject) { + event = eventObject; + object.off(event.type, listener2); + }) + .on('shallowclone', listener2) + .emit('shallowclone'); + + ok(event.listener2); + }); + + test('emits a custom event object', function() { + var event = Benchmark.Event('custom'), + object = Constructor(); + + object.on('custom', function(eventObject) { eventObject.touched = true; }); + object.emit(event); + ok(event.touched); + }); + + test('sets `event.result` correctly', function() { + var event = Benchmark.Event('result'), + object = Constructor(); + + object.on('result', function() { return 'x'; }); + object.emit(event); + equal(event.result, 'x'); + }); + + test('sets `event.type` correctly', function() { + var event, + object = Constructor(); + + object.on('type', function(eventObj) { + event = eventObj; + }); + + object.emit('type'); + equal(event.type, 'type'); + }); + }()); + + /*------------------------------------------------------------------------*/ + + QUnit.module(namespace + '#listeners'); + + (function() { + test('returns the correct listeners', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + deepEqual(object.listeners('x'), [listener]); + }); + + test('returns an array and initializes previously uninitialized listeners', function() { + var object = Constructor(); + deepEqual(object.listeners('x'), []); + deepEqual(object.events, { 'x': [] }); + }); + }()); + + /*------------------------------------------------------------------------*/ + + QUnit.module(namespace + '#off'); + + (function() { + test('returns the benchmark', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + equal(object.off('x', listener), object); + }); + + test('will ignore inherited properties of the event cache', function() { + var Dummy = function() { }, + listener = function() { }, + object = Constructor(); + + Dummy.prototype.x = [listener]; + object.events = new Dummy; + + object.off('x', listener); + deepEqual(object.events.x, [listener]); + }); + + test('handles an event type and listener', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + object.off('x', listener); + deepEqual(object.events.x, []); + }); + + test('handles unregistering duplicate listeners', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + object.on('x', listener); + + var events = object.events; + object.off('x', listener); + deepEqual(events.x, [listener]); + + object.off('x', listener); + deepEqual(events.x, []); + }); + + test('handles a non-registered listener', function() { + var object = Constructor(); + object.off('x', function() { }); + equal(object.events, undefined); + }); + + test('handles space separated event type and listener', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + object.on('y', listener); + + var events = object.events; + object.off('x y', listener); + deepEqual(events.x, []); + deepEqual(events.y, []); + }); + + test('handles space separated event type and no listener', function() { + var listener1 = function() { }, + listener2 = function() { }, + object = Constructor(); + + object.on('x', listener1); + object.on('y', listener2); + + var events = object.events; + object.off('x y'); + deepEqual(events.x, []); + deepEqual(events.y, []); + }); + + test('handles no arguments', function() { + var listener1 = function() { }, + listener2 = function() { }, + listener3 = function() { }, + object = Constructor(); + + object.on('x', listener1); + object.on('y', listener2); + object.on('z', listener3); + + var events = object.events; + object.off(); + deepEqual(events.x, []); + deepEqual(events.y, []); + deepEqual(events.z, []); + }); + }()); + + /*------------------------------------------------------------------------*/ + + QUnit.module(namespace + '#on'); + + (function() { + test('returns the benchmark', function() { + var listener = function() { }, + object = Constructor(); + + equal(object.on('x', listener), object); + }); + + test('will ignore inherited properties of the event cache', function() { + var Dummy = function() { }, + listener1 = function() { }, + listener2 = function() { }, + object = Constructor(); + + Dummy.prototype.x = [listener1]; + object.events = new Dummy; + + object.on('x', listener2); + deepEqual(object.events.x, [listener2]); + }); + + test('handles an event type and listener', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + deepEqual(object.events.x, [listener]); + }); + + test('handles registering duplicate listeners', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x', listener); + object.on('x', listener); + deepEqual(object.events.x, [listener, listener]); + }); + + test('handles space separated event type and listener', function() { + var listener = function() { }, + object = Constructor(); + + object.on('x y', listener); + + var events = object.events; + deepEqual(events.x, [listener]); + deepEqual(events.y, [listener]); + }); + }()); + }); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#abort'); + + (function() { + test('igores abort calls when the suite isn\'t running', function() { + var fired = false; + var suite = Benchmark.Suite('suite', { + 'onAbort': function() { fired = true; } + }); + + suite.add('foo', function() { }); + suite.abort(); + equal(fired, false); + }); + + test('ignores abort calls from `Benchmark.Suite#reset` when the suite isn\'t running', function() { + var fired = false; + var suite = Benchmark.Suite('suite', { + 'onAbort': function() { fired = true; } + }); + + suite.add('foo', function() { }); + suite.reset(); + equal(fired, false); + }); + + asyncTest('emits an abort event when running', function() { + var fired = false; + + Benchmark.Suite({ + 'onAbort': function() { fired = true; } + }) + .on('start', function() { + this.abort(); + }) + .on('complete', function() { + ok(fired); + QUnit.start(); + }) + .add(function(){ }) + .run({ 'async': true }); + }); + + asyncTest('emits an abort event after calling `Benchmark.Suite#reset`', function() { + var fired = false; + + Benchmark.Suite({ + 'onAbort': function() { fired = true; } + }) + .on('start', function() { + this.reset(); + }) + .on('complete', function() { + ok(fired); + QUnit.start(); + }) + .add(function(){ }) + .run({ 'async': true }); + }); + + asyncTest('should abort deferred benchmark', function() { + var fired = false, + suite = Benchmark.Suite(); + + suite.on('complete', function() { + equal(fired, false); + QUnit.start(); + }) + .add('a', { + 'defer': true, + 'fn': function(deferred) { + // avoid test inlining + suite.name; + // delay resolve + setTimeout(function() { + deferred.resolve(); + suite.abort(); + }, 10); + } + }) + .add('b', { + 'defer': true, + 'fn': function(deferred) { + // avoid test inlining + suite.name; + // delay resolve + setTimeout(function() { + deferred.resolve(); + fired = true; + }, 10); + } + }) + .run(); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#concat'); + + (function() { + var args = arguments; + + test('doesn\'t treat an arguments object like an array', function() { + var suite = Benchmark.Suite(); + deepEqual(suite.concat(args), [args]); + }); + + test('flattens array arguments', function() { + var suite = Benchmark.Suite(); + deepEqual(suite.concat([1, 2], 3, [4, 5]), [1, 2, 3, 4, 5]); + }); + + test('supports concating sparse arrays', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[2] = 2; + suite.length = 3; + + var actual = suite.concat(3); + deepEqual(actual, [0, undefined, 2, 3]); + equal('1' in actual, false); + }); + + test('supports sparse arrays as arguments', function() { + var suite = Benchmark.Suite(), + sparse = []; + + sparse[0] = 0; + sparse[2] = 2; + sparse.length = 3; + + var actual = suite.concat(sparse); + deepEqual(actual, [0, undefined, 2]); + equal('1' in actual, false); + }); + + test('creates a new array', function() { + var suite = Benchmark.Suite(); + ok(suite.concat(1) !== suite); + }); + }(1, 2, 3)); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#reverse'); + + (function() { + test('reverses the element order', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 1; + suite.length = 2; + + var actual = suite.reverse(); + equal(actual, suite); + deepEqual(slice.call(actual), [1, 0]); + }); + + test('supports reversing sparse arrays', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[2] = 2; + suite.length = 3; + + var actual = suite.reverse(); + equal(actual, suite); + deepEqual(slice.call(actual), [2, undefined, 0]); + equal('1' in actual, false); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#shift'); + + (function() { + test('removes the first element', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 1; + suite.length = 2; + + var actual = suite.shift(); + equal(actual, 0); + deepEqual(slice.call(suite), [1]); + }); + + test('shifts an object with no elements', function() { + var suite = Benchmark.Suite(), + actual = suite.shift(); + + equal(actual, undefined); + deepEqual(slice.call(suite), []); + }); + + test('should have no elements when length is 0 after shift', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite.length = 1; + suite.shift(); + + // ensure element is removed + equal('0' in suite, false); + equal(suite.length, 0); + }); + + test('supports shifting sparse arrays', function() { + var suite = Benchmark.Suite(); + suite[1] = 1; + suite[3] = 3; + suite.length = 4; + + var actual = suite.shift(); + equal(actual, undefined); + deepEqual(slice.call(suite), [1, undefined, 3]); + equal('1' in suite, false); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#slice'); + + (function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 1; + suite[2] = 2; + suite[3] = 3; + suite.length = 4; + + test('works with no arguments', function() { + var actual = suite.slice(); + deepEqual(actual, [0, 1, 2, 3]); + ok(suite !== actual); + }); + + test('works with positive `start` argument', function() { + var actual = suite.slice(2); + deepEqual(actual, [2, 3]); + ok(suite !== actual); + }); + + test('works with positive `start` and `end` arguments', function() { + var actual = suite.slice(1, 3); + deepEqual(actual, [1, 2]); + ok(suite !== actual); + }); + + test('works with `end` values exceeding length', function() { + var actual = suite.slice(1, 10); + deepEqual(actual, [1, 2, 3]); + ok(suite !== actual); + }); + + test('works with negative `start` and `end` arguments', function() { + var actual = suite.slice(-3, -1); + deepEqual(actual, [1, 2]); + ok(suite !== actual); + }); + + test('works with an extreme negative `end` value', function() { + var actual = suite.slice(1, -10); + deepEqual(actual, []); + equal('-1' in actual, false); + ok(suite !== actual); + }); + + test('supports slicing sparse arrays', function() { + var sparse = Benchmark.Suite(); + sparse[1] = 1; + sparse[3] = 3; + sparse.length = 4; + + var actual = sparse.slice(0, 2); + deepEqual(actual, [undefined, 1]); + equal('0' in actual, false); + + actual = sparse.slice(1); + deepEqual(actual, [1, undefined, 3]); + equal('1' in actual, false); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#splice'); + + (function() { + test('works with no arguments', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite.length = 1; + + var actual = suite.splice(); + deepEqual(actual, []); + deepEqual(slice.call(suite), [0]); + }); + + test('works with only the `start` argument', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 1; + suite.length = 2; + + var actual = suite.splice(1); + deepEqual(actual, [1]); + deepEqual(slice.call(suite), [0]); + }); + + test('should have no elements when length is 0 after splice', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite.length = 1 + suite.splice(0, 1); + + // ensure element is removed + equal('0' in suite, false); + equal(suite.length, 0); + }); + + test('works with positive `start` argument', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 3; + suite.length = 2; + + var actual = suite.splice(1, 0, 1, 2); + deepEqual(actual, []); + deepEqual(slice.call(suite), [0, 1, 2, 3]); + }); + + test('works with positive `start` and `deleteCount` arguments', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 3; + suite.length = 2; + + var actual = suite.splice(1, 1, 1, 2); + deepEqual(actual, [3]); + deepEqual(slice.call(suite), [0, 1, 2]); + }); + + test('works with `deleteCount` values exceeding length', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 3; + suite.length = 2; + + var actual = suite.splice(1, 10, 1, 2); + deepEqual(actual, [3]); + deepEqual(slice.call(suite), [0, 1, 2]); + }); + + test('works with negative `start` and `deleteCount` arguments', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 3; + suite.length = 2; + + var actual = suite.splice(-1, -1, 1, 2); + deepEqual(actual, []); + deepEqual(slice.call(suite), [0, 1, 2, 3]); + }); + + test('works with an extreme negative `deleteCount` value', function() { + var suite = Benchmark.Suite(); + suite[0] = 0; + suite[1] = 3; + suite.length = 2; + + var actual = suite.splice(0, -10, 1, 2); + deepEqual(actual, []); + deepEqual(slice.call(suite), [1, 2, 0, 3]); + }); + + test('supports splicing sparse arrays', function() { + var suite = Benchmark.Suite(); + suite[1] = 1; + suite[3] = 3; + suite.length = 4; + + var actual = suite.splice(1, 2, 1, 2); + deepEqual(actual, [1, undefined]); + equal(actual.length, 2); + deepEqual(slice.call(suite), [undefined, 1, 2, 3]); + equal('0' in suite, false); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite#unshift'); + + (function() { + test('adds a first element', function() { + var suite = Benchmark.Suite(); + suite[0] = 1; + suite.length = 1; + + var actual = suite.unshift(0); + equal(actual, 2); + deepEqual(slice.call(suite), [0, 1]); + }); + + test('adds multiple elements to the front', function() { + var suite = Benchmark.Suite(); + suite[0] = 3; + suite.length = 1; + + var actual = suite.unshift(0, 1, 2); + equal(actual, 4); + deepEqual(slice.call(suite), [0, 1, 2, 3]); + }); + + test('supports unshifting sparse arrays', function() { + var suite = Benchmark.Suite(); + suite[1] = 2; + suite.length = 2; + + var actual = suite.unshift(0); + equal(actual, 3); + deepEqual(slice.call(suite), [0, undefined, 2]); + equal('1' in suite, false); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite filtered results onComplete'); + + (function() { + var count = 0, + suite = Benchmark.Suite(); + + suite.add('a', function() { + count++; + }) + .add('b', function() { + for (var i = 0; i < 1e6; i++) { + count++; + } + }) + .add('c', function() { + throw new TypeError; + }); + + asyncTest('should filter by fastest', function() { + suite.on('complete', function() { + suite.off(); + deepEqual(this.filter('fastest').pluck('name'), ['a']); + QUnit.start(); + }) + .run({ 'async': true }); + }); + + asyncTest('should filter by slowest', function() { + suite.on('complete', function() { + suite.off(); + deepEqual(this.filter('slowest').pluck('name'), ['b']); + QUnit.start(); + }) + .run({ 'async': true }); + }); + + asyncTest('should filter by successful', function() { + suite.on('complete', function() { + suite.off(); + deepEqual(this.filter('successful').pluck('name'), ['a', 'b']); + QUnit.start(); + }) + .run({ 'async': true }); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.Suite event flow'); + + (function() { + var events = [], + callback = function(event) { events.push(event); }; + + var suite = Benchmark.Suite('suite', { + 'onAdd': callback, + 'onAbort': callback, + 'onClone': callback, + 'onError': callback, + 'onStart': callback, + 'onCycle': callback, + 'onComplete': callback, + 'onReset': callback + }) + .add('bench', function() { + throw null; + }, { + 'onAbort': callback, + 'onClone': callback, + 'onError': callback, + 'onStart': callback, + 'onCycle': callback, + 'onComplete': callback, + 'onReset': callback + }) + .run({ 'async': false }); + + // first Suite#onAdd + test('should emit the suite "add" event first', function() { + var event = events[0]; + ok(event.type == 'add' && event.currentTarget.name == 'suite' && event.target.name == 'bench'); + }); + + // next we start the Suite because no reset was needed + test('should emit the suite "start" event', function() { + var event = events[1]; + ok(event.type == 'start' && event.currentTarget.name == 'suite' && event.target.name == 'bench'); + }); + + // and so start the first benchmark + test('should emit the benchmark "start" event', function() { + var event = events[2]; + ok(event.type == 'start' && event.currentTarget.name == 'bench'); + }); + + // oh no! we abort because of an error + test('should emit the benchmark "error" event', function() { + var event = events[3]; + ok(event.type == 'error' && event.currentTarget.name == 'bench'); + }); + + // benchmark error triggered + test('should emit the benchmark "abort" event', function() { + var event = events[4]; + ok(event.type == 'abort' && event.currentTarget.name == 'bench'); + }); + + // we reset the benchmark as part of the abort + test('should emit the benchmark "reset" event', function() { + var event = events[5]; + ok(event.type == 'reset' && event.currentTarget.name == 'bench'); + }); + + // benchmark is cycle is finished + test('should emit the benchmark "cycle" event', function() { + var event = events[6]; + ok(event.type == 'cycle' && event.currentTarget.name == 'bench'); + }); + + // benchmark is complete + test('should emit the benchmark "complete" event', function() { + var event = events[7]; + ok(event.type == 'complete' && event.currentTarget.name == 'bench'); + }); + + // the benchmark error triggers a Suite error + test('should emit the suite "error" event', function() { + var event = events[8]; + ok(event.type == 'error' && event.currentTarget.name == 'suite' && event.target.name == 'bench'); + }); + + // the Suite cycle finishes + test('should emit the suite "cycle" event', function() { + var event = events[9]; + ok(event.type == 'cycle' && event.currentTarget.name == 'suite' && event.target.name == 'bench'); + }); + + // the Suite completes + test('finally it should emit the suite "complete" event', function() { + var event = events[10]; + ok(event.type == 'complete' && event.currentTarget.name == 'suite' && event.target.name == 'bench'); + }); + + test('emitted all expected events', function() { + ok(events.length == 11); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Deferred benchmarks'); + + (function() { + asyncTest('should run a deferred benchmark correctly', function() { + Benchmark(function(deferred) { + setTimeout(function() { deferred.resolve(); }, 1e3); + }, { + 'defer': true, + 'onComplete': function() { + equal(this.hz.toFixed(0), 1); + QUnit.start(); + } + }) + .run(); + }); + + asyncTest('should run with string values for "fn", "setup", and "teardown"', function() { + Benchmark({ + 'defer': true, + 'setup': 'var x = [3, 2, 1];', + 'fn': 'setTimeout(function() { x.sort(); deferred.resolve(); }, 10);', + 'teardown': 'x.length = 0;', + 'onComplete': function() { + ok(true); + QUnit.start(); + } + }) + .run(); + }); + + asyncTest('should run recursively', function() { + Benchmark({ + 'defer': true, + 'setup': 'var x = [3, 2, 1];', + 'fn': 'for (var i = 0; i < 100; i++) x[ i % 2 ? "sort" : "reverse" ](); deferred.resolve();', + 'teardown': 'x.length = 0;', + 'onComplete': function() { + ok(true); + QUnit.start(); + } + }) + .run(); + }); + + asyncTest('should execute "setup", "fn", and "teardown" in correct order', function() { + var fired = []; + + Benchmark({ + 'defer': true, + 'setup': function() { + fired.push('setup'); + }, + 'fn': function(deferred) { + fired.push('fn'); + setTimeout(function() { deferred.resolve(); }, 10); + }, + 'teardown': function() { + fired.push('teardown'); + }, + 'onComplete': function() { + var actual = fired.join().replace(/(fn,)+/g, '$1').replace(/(setup,fn,teardown(?:,|$))+/, '$1'); + equal(actual, 'setup,fn,teardown'); + QUnit.start(); + } + }) + .run(); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('Benchmark.deepClone'); + + (function() { + asyncTest('avoids call stack limits', function() { + var result, + count = 0, + object = {}, + recurse = function() { count++; recurse(); }; + + setTimeout(function() { + ok(result, 'avoids call stack limits (stack limit is ' + (count - 1) + ')'); + QUnit.start(); + }, 15); + + if (toString.call(window.java) == '[object JavaPackage]') { + // Java throws uncatchable errors on call stack overflows, so to avoid + // them I chose a number higher than Rhino's call stack limit without + // dynamically testing for the actual limit + count = 3e3; + } else { + try { recurse(); } catch(e) { } + } + + // exceed limit + count++; + for (var i = 0, sub = object; i <= count; i++) { + sub = sub[i] = {}; + } + + try { + for (var i = 0, sub = Benchmark.deepClone(object); sub = sub[i]; i++) { } + result = --i == count; + } catch(e) { } + }); + }()); + + /*--------------------------------------------------------------------------*/ + + // explicitly call `QUnit.start()` for Narwhal, Rhino, and RingoJS + if (!window.document) { + QUnit.start(); + } +}(typeof global == 'object' && global || this)); diff --git a/web/src/vendor/benchmark/vendor/docdown/LICENSE.txt b/web/src/vendor/benchmark/vendor/docdown/LICENSE.txt new file mode 100644 index 00000000..dadad22f --- /dev/null +++ b/web/src/vendor/benchmark/vendor/docdown/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/web/src/vendor/benchmark/vendor/docdown/README.md b/web/src/vendor/benchmark/vendor/docdown/README.md new file mode 100644 index 00000000..7e2665e3 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/docdown/README.md @@ -0,0 +1,33 @@ +# Docdown <sup>v1.0.0</sup> + +A simple JSDoc to Markdown documentation generator. + +## Documentation + +The documentation for Docdown can be viewed here: [/doc/README.md](https://github.com/jdalton/docdown/blob/master/doc/README.md#readme) + +For a list of upcoming features, check out our [roadmap](https://github.com/jdalton/docdown/wiki/Roadmap). + +## Installation and usage + +Usage example: + +```php +require("docdown.php"); + +// generate Markdown +$markdown = docdown(array( + "path" => $filepath, + "url" => "https://github.com/username/project/blob/master/my.js" +)); +``` + +## Author + +* [John-David Dalton](http://allyoucanleet.com/) + [](https://twitter.com/jdalton "Follow @jdalton on Twitter") + +## Contributors + +* [Mathias Bynens](http://mathiasbynens.be/) + [](https://twitter.com/mathias "Follow @mathias on Twitter") diff --git a/web/src/vendor/benchmark/vendor/docdown/docdown.php b/web/src/vendor/benchmark/vendor/docdown/docdown.php new file mode 100644 index 00000000..6a960d49 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/docdown/docdown.php @@ -0,0 +1,38 @@ +<?php +/*! + * Docdown v1.0.0-pre + * Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/> + * Available under MIT license <http://mths.be/mit> + */ +require(dirname(__FILE__) . '/src/DocDown/Generator.php'); + +/** + * Generates Markdown from JSDoc entries in a given file. + * + * @param {Array} [$options=array()] The options array. + * @returns {String} The generated Markdown. + * @example + * + * // specify a file path + * $markdown = docdown(array( + * // path to js file + * 'path' => $filepath, + * // url used to reference line numbers in code + * 'url' => 'https://github.com/username/project/blob/master/my.js' + * )); + * + * // or pass raw js + * $markdown = docdown(array( + * // raw JavaScript source + * 'source' => $rawJS, + * // documentation title + * 'title' => 'My API Documentation', + * // url used to reference line numbers in code + * 'url' => 'https://github.com/username/project/blob/master/my.js' + * )); + */ +function docdown( $options = array() ) { + $gen = new Generator($options); + return $gen->generate(); +} +?>
\ No newline at end of file diff --git a/web/src/vendor/benchmark/vendor/docdown/src/DocDown/Entry.php b/web/src/vendor/benchmark/vendor/docdown/src/DocDown/Entry.php new file mode 100644 index 00000000..e7924c0e --- /dev/null +++ b/web/src/vendor/benchmark/vendor/docdown/src/DocDown/Entry.php @@ -0,0 +1,304 @@ +<?php + +/** + * A class to simplify parsing a single JSDoc entry. + */ +class Entry { + + /** + * The documentation entry. + * + * @memberOf Entry + * @type String + */ + public $entry = ''; + + /** + * The language highlighter used for code examples. + * + * @memberOf Entry + * @type String + */ + public $lang = ''; + + /** + * The source code. + * + * @memberOf Entry + * @type String + */ + public $source = ''; + + /*--------------------------------------------------------------------------*/ + + /** + * The Entry constructor. + * + * @constructor + * @param {String} $entry The documentation entry to analyse. + * @param {String} $source The source code. + * @param {String} $lang The language highlighter used for code examples. + */ + public function __construct( $entry, $source, $lang = 'js' ) { + $this->entry = $entry; + $this->lang = $lang; + $this->source = str_replace(PHP_EOL, "\n", $source); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Extracts the documentation entries from source code. + * + * @static + * @memberOf Entry + * @param {String} $source The source code. + * @returns {Array} The array of entries. + */ + public static function getEntries( $source ) { + preg_match_all('#/\*\*(?![-!])[\s\S]*?\*/\s*[^\n]+#', $source, $result); + return array_pop($result); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Checks if the entry is a function reference. + * + * @private + * @memberOf Entry + * @returns {Boolean} Returns `true` if the entry is a function reference, else `false`. + */ + private function isFunction() { + return !!( + $this->isCtor() || + count($this->getParams()) || + count($this->getReturns()) || + preg_match('/\*\s*@function\b/', $this->entry) + ); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Extracts the function call from the entry. + * + * @memberOf Entry + * @returns {String} The function call. + */ + public function getCall() { + preg_match('#\*/\s*(?:function ([^(]*)|(.*?)(?=[:=,]|return\b))#', $this->entry, $result); + if ($result = array_pop($result)) { + $result = array_pop(explode('var ', trim(trim(array_pop(explode('.', $result))), "'"))); + } + // resolve name + // avoid $this->getName() because it calls $this->getCall() + preg_match('#\*\s*@name\s+([^\n]+)#', $this->entry, $name); + if (count($name)) { + $name = trim($name[1]); + } else { + $name = $result; + } + // compile function call syntax + if ($this->isFunction()) { + // compose parts + $result = array($result); + $params = $this->getParams(); + foreach ($params as $param) { + $result[] = $param[1]; + } + // format + $result = $name .'('. implode(array_slice($result, 1), ', ') .')'; + $result = str_replace(', [', ' [, ', str_replace('], [', ', ', $result)); + } + return $result ? $result : $name; + } + + /** + * Extracts the entry description. + * + * @memberOf Entry + * @returns {String} The entry description. + */ + public function getDesc() { + preg_match('#/\*\*(?:\s*\*)?([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); + if (count($result)) { + $type = $this->getType(); + $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = ($type == 'Function' ? '' : '(' . str_replace('|', ', ', trim($type, '{}')) . '): ') . $result; + } + return $result; + } + + /** + * Extracts the entry `example` data. + * + * @memberOf Entry + * @returns {String} The entry `example` data. + */ + public function getExample() { + preg_match('#\*\s*@example\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); + if (count($result)) { + $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', "\n", $result[1])); + $result = '```' . $this->lang . "\n" . $result . "\n```"; + } + return $result; + } + + /** + * Resolves the line number of the entry. + * + * @memberOf Entry + * @returns {Number} The line number. + */ + public function getLineNumber() { + preg_match_all('/\n/', substr($this->source, 0, strrpos($this->source, $this->entry) + strlen($this->entry)), $lines); + return count(array_pop($lines)) + 1; + } + + /** + * Extracts the entry `member` data. + * + * @memberOf Entry + * @param {Number} $index The index of the array value to return. + * @returns {Array|String} The entry `member` data. + */ + public function getMembers( $index = null ) { + preg_match('#\*\s*@member(?:Of)?\s+([^\n]+)#', $this->entry, $result); + if (count($result)) { + $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + $result = preg_split('/,\s*/', $result); + } + return $index !== null ? @$result[$index] : $result; + } + + /** + * Extracts the entry `name` data. + * + * @memberOf Entry + * @returns {String} The entry `name` data. + */ + public function getName() { + preg_match('#\*\s*@name\s+([^\n]+)#', $this->entry, $result); + if (count($result)) { + $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + } else { + $result = array_shift(explode('(', $this->getCall())); + } + return $result; + } + + /** + * Extracts the entry `param` data. + * + * @memberOf Entry + * @param {Number} $index The index of the array value to return. + * @returns {Array} The entry `param` data. + */ + public function getParams( $index = null ) { + preg_match_all('#\*\s*@param\s+\{([^}]+)\}\s+(\[.+\]|[$\w]+)\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#i', $this->entry, $result); + if (count($result = array_filter(array_slice($result, 1)))) { + // repurpose array + foreach ($result as $param) { + foreach ($param as $key => $value) { + if (!is_array($result[0][$key])) { + $result[0][$key] = array(); + } + $result[0][$key][] = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $value)); + } + } + $result = $result[0]; + } + return $index !== null ? @$result[$index] : $result; + } + + /** + * Extracts the entry `returns` data. + * + * @memberOf Entry + * @returns {String} The entry `returns` data. + */ + public function getReturns() { + preg_match('#\*\s*@returns\s+\{([^}]+)\}\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result); + if (count($result)) { + $result = array_map('trim', array_slice($result, 1)); + $result[0] = str_replace('|', ', ', $result[0]); + $result[1] = preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1]); + } + return $result; + } + + /** + * Extracts the entry `type` data. + * + * @memberOf Entry + * @returns {String} The entry `type` data. + */ + public function getType() { + preg_match('#\*\s*@type\s+([^\n]+)#', $this->entry, $result); + if (count($result)) { + $result = trim(preg_replace('/(?:^|\n)\s*\* ?/', ' ', $result[1])); + } else { + $result = $this->isFunction() ? 'Function' : 'Unknown'; + } + return $result; + } + + /** + * Checks if an entry is a constructor. + * + * @memberOf Entry + * @returns {Boolean} Returns true if a constructor, else false. + */ + public function isCtor() { + return !!preg_match('/\*\s*@constructor\b/', $this->entry); + } + + /** + * Checks if an entry *is* assigned to a prototype. + * + * @memberOf Entry + * @returns {Boolean} Returns true if assigned to a prototype, else false. + */ + public function isPlugin() { + return !$this->isCtor() && !$this->isPrivate() && !$this->isStatic(); + } + + /** + * Checks if an entry is private. + * + * @memberOf Entry + * @returns {Boolean} Returns true if private, else false. + */ + public function isPrivate() { + return !!preg_match('/\*\s*@private\b/', $this->entry) || strrpos($this->entry, '@') === false; + } + + /** + * Checks if an entry is *not* assigned to a prototype. + * + * @memberOf Entry + * @returns {Boolean} Returns true if not assigned to a prototype, else false. + */ + public function isStatic() { + $public = !$this->isPrivate(); + $result = $public && !!preg_match('/\*\s*@static\b/', $this->entry); + + // set in cases where it isn't explicitly stated + if ($public && !$result) { + if ($parent = array_pop(preg_split('/[#.]/', $this->getMembers(0)))) { + foreach (Entry::getEntries($this->source) as $entry) { + $entry = new Entry($entry, $this->source); + if ($entry->getName() == $parent) { + $result = !$entry->isCtor(); + break; + } + } + } else { + $result = true; + } + } + return $result; + } +} +?>
\ No newline at end of file diff --git a/web/src/vendor/benchmark/vendor/docdown/src/DocDown/Generator.php b/web/src/vendor/benchmark/vendor/docdown/src/DocDown/Generator.php new file mode 100644 index 00000000..6c1873d8 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/docdown/src/DocDown/Generator.php @@ -0,0 +1,416 @@ +<?php + +require(dirname(__FILE__) . "/Entry.php"); + +/** + * Generates Markdown from JSDoc entries. + */ +class Generator { + + /** + * An array of JSDoc entries. + * + * @memberOf Generator + * @type Array + */ + public $entries = array(); + + /** + * An options array used to configure the generator. + * + * @memberOf Generator + * @type Array + */ + public $options = array(); + + /** + * The entire file's source code. + * + * @memberOf Generator + * @type String + */ + public $source = ''; + + /*--------------------------------------------------------------------------*/ + + /** + * The Generator constructor. + * + * @constructor + * @param {String} $source The source code to parse. + * @param {Array} $options The options array. + */ + public function __construct( $source, $options = array() ) { + // juggle arguments + if (is_array($source)) { + $options = $source; + } else { + $options['source'] = $source; + } + if (isset($options['source']) && realpath($options['source'])) { + $options['path'] = $options['source']; + } + if (isset($options['path'])) { + preg_match('/(?<=\.)[a-z]+$/', $options['path'], $ext); + $options['source'] = file_get_contents($options['path']); + $ext = array_pop($ext); + + if (!isset($options['lang']) && $ext) { + $options['lang'] = $ext; + } + if (!isset($options['title'])) { + $options['title'] = ucfirst(basename($options['path'])) . ' API documentation'; + } + } + if (!isset($options['lang'])) { + $options['lang'] = 'js'; + } + + $this->options = $options; + $this->source = str_replace(PHP_EOL, "\n", $options['source']); + $this->entries = Entry::getEntries($this->source); + + foreach ($this->entries as $index => $value) { + $this->entries[$index] = new Entry($value, $this->source, $options['lang']); + } + } + + /*--------------------------------------------------------------------------*/ + + /** + * Performs common string formatting operations. + * + * @private + * @static + * @memberOf Generator + * @param {String} $string The string to format. + * @returns {String} The formatted string. + */ + private static function format($string) { + $counter = 0; + + // tokenize inline code snippets + preg_match_all('/`[^`]+`/', $string, $tokenized); + $tokenized = $tokenized[0]; + foreach ($tokenized as $snippet) { + $string = str_replace($snippet, '__token' . ($counter++) .'__', $string); + } + + // italicize parentheses + $string = preg_replace('/(^|\s)(\([^)]+\))/', '$1*$2*', $string); + + // mark numbers as inline code + $string = preg_replace('/ (-?\d+(?:.\d+)?)(?!\.[^\n])/', ' `$1`', $string); + + // detokenize inline code snippets + $counter = 0; + foreach ($tokenized as $snippet) { + $string = str_replace('__token' . ($counter++) . '__', $snippet, $string); + } + + return trim($string); + } + + /** + * Modify a string by replacing named tokens with matching assoc. array values. + * + * @private + * @static + * @memberOf Generator + * @param {String} $string The string to modify. + * @param {Array|Object} $object The template object. + * @returns {String} The modified string. + */ + private static function interpolate($string, $object) { + preg_match_all('/#\{([^}]+)\}/', $string, $tokens); + $tokens = array_unique(array_pop($tokens)); + + foreach ($tokens as $token) { + $pattern = '/#\{' . $token . '\}/'; + $replacement = ''; + + if (is_object($object)) { + preg_match('/\(([^)]+?)\)$/', $token, $args); + $args = preg_split('/,\s*/', array_pop($args)); + $method = 'get' . ucfirst(str_replace('/\([^)]+?\)$/', '', $token)); + + if (method_exists($object, $method)) { + $replacement = (string) call_user_func_array(array($object, $method), $args); + } else if (isset($object->{$token})) { + $replacement = (string) $object->{$token}; + } + } else if (isset($object[$token])) { + $replacement = (string) $object[$token]; + } + $string = preg_replace($pattern, trim($replacement), $string); + } + return Generator::format($string); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Resolves the entry's hash used to navigate the documentation. + * + * @private + * @memberOf Generator + * @param {Number|Object} $entry The entry object. + * @param {String} $member The name of the member. + * @returns {String} The url hash. + */ + private function getHash( $entry, $member = '' ) { + $entry = is_numeric($entry) ? $this->entries[$entry] : $entry; + $member = !$member ? $entry->getMembers(0) : $member; + $result = ($member ? $member . ($entry->isPlugin() ? 'prototype' : '') : '') . $entry->getCall(); + $result = preg_replace('/\(\[|\[\]/', '', $result); + $result = preg_replace('/[ =\'"{}.()\]]/', '', $result); + $result = preg_replace('/[[#,]/', '-', $result); + return strtolower($result); + } + + /** + * Resolves the entry's url for the specific line number. + * + * @private + * @memberOf Generator + * @param {Number|Object} $entry The entry object. + * @returns {String} The url. + */ + private function getLineUrl( $entry ) { + $entry = is_numeric($entry) ? $this->entries($entry) : $entry; + return $this->options['url'] . '#L' . $entry->getLineNumber(); + } + + /** + * Extracts the character used to separate the entry's name from its member. + * + * @private + * @memberOf Generator + * @param {Number|Object} $entry The entry object. + * @returns {String} The separator. + */ + private function getSeparator( $entry ) { + $entry = is_numeric($entry) ? $this->entries($entry) : $entry; + return $entry->isPlugin() ? '.prototype.' : '.'; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Generates Markdown from JSDoc entries. + * + * @memberOf Generator + * @returns {String} The rendered Markdown. + */ + public function generate() { + $api = array(); + $compiling = false; + $openTag = "\n<!-- div -->\n"; + $closeTag = "\n<!-- /div -->\n"; + $result = array('# ' . $this->options['title']); + $toc = 'toc'; + + // initialize $api array + foreach ($this->entries as $entry) { + + if (!$entry->isPrivate()) { + $name = $entry->getName(); + $members = $entry->getMembers(); + $members = count($members) ? $members : array(''); + + foreach ($members as $member) { + // create api category arrays + if (!isset($api[$member]) && $member) { + $api[$member] = new Entry('', '', $entry->lang); + $api[$member]->static = array(); + $api[$member]->plugin = array(); + } + // append entry to api category + if (!$member || $entry->isCtor() || ($entry->getType() == 'Object' && + !preg_match('/[=:]\s*null\s*[,;]?$/', $entry->entry))) { + $member = ($member ? $member . ($entry->isPlugin() ? '#' : '.') : '') . $name; + $entry->static = @$api[$member] ? $api[$member]->static : array(); + $entry->plugin = @$api[$member] ? $api[$member]->plugin : array(); + $api[$member] = $entry; + } + else if ($entry->isStatic()) { + $api[$member]->static[] = $entry; + } else if (!$entry->isCtor()) { + $api[$member]->plugin[] = $entry; + } + } + } + } + + /*------------------------------------------------------------------------*/ + + // custom sort for root level entries + // TODO: see how well it handles deeper namespace traversal + function sortCompare($a, $b) { + $score = array( 'a' => 0, 'b' => 0); + foreach (array( 'a' => $a, 'b' => $b) as $key => $value) { + // capitalized keys that represent constructor properties are last + if (preg_match('/[#.][A-Z]/', $value)) { + $score[$key] = 0; + } + // lowercase keys with prototype properties are next to last + else if (preg_match('/#[a-z]/', $value)) { + $score[$key] = 1; + } + // lowercase keys with static properties next to first + else if (preg_match('/\.[a-z]/', $value)) { + $score[$key] = 2; + } + // lowercase keys with no properties are first + else if (preg_match('/^[^#.]+$/', $value)) { + $score[$key] = 3; + } + } + $score = $score['b'] - $score['a']; + return $score ? $score : strcasecmp($a, $b); + } + + uksort($api, 'sortCompare'); + + // sort static and plugin sub-entries + foreach ($api as $entry) { + foreach (array('static', 'plugin') as $kind) { + $sortBy = array( 'a' => array(), 'b' => array(), 'c' => array() ); + foreach ($entry->{$kind} as $subentry) { + $name = $subentry->getName(); + // functions w/o ALL-CAPs names are last + $sortBy['a'][] = $subentry->getType() == 'Function' && !preg_match('/^[A-Z_]+$/', $name); + // ALL-CAPs properties first + $sortBy['b'][] = preg_match('/^[A-Z_]+$/', $name); + // lowercase alphanumeric sort + $sortBy['c'][] = strtolower($name); + } + array_multisort($sortBy['a'], SORT_ASC, $sortBy['b'], SORT_DESC, $sortBy['c'], SORT_ASC, $entry->{$kind}); + } + } + + /*------------------------------------------------------------------------*/ + + // compile TOC + $result[] = $openTag; + + foreach ($api as $key => $entry) { + $entry->hash = $this->getHash($entry); + $entry->href = $this->getLineUrl($entry); + + $member = $entry->getMembers(0); + $member = ($member ? $member . ($entry->isPlugin() ? '.prototype.' : '.') : '') . $entry->getName(); + + $entry->member = preg_replace('/' . $entry->getName() . '$/', '', $member); + + $compiling = $compiling ? ($result[] = $closeTag) : true; + + // assign TOC hash + if (count($result) == 2) { + $toc = $member; + } + + // add root entry + array_push( + $result, + $openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $member . '`', + Generator::interpolate('* [`' . $member . '`](##{hash})', $entry) + ); + + // add static and plugin sub-entries + foreach (array('static', 'plugin') as $kind) { + if ($kind == 'plugin' && count($entry->plugin)) { + array_push( + $result, + $closeTag, + $openTag, + '## `' . $member . ($entry->isCtor() ? '.prototype`' : '`') + ); + } + foreach ($entry->{$kind} as $subentry) { + $subentry->hash = $this->getHash($subentry); + $subentry->href = $this->getLineUrl($subentry); + $subentry->member = $member; + $subentry->separator = $this->getSeparator($subentry); + $result[] = Generator::interpolate('* [`#{member}#{separator}#{name}`](##{hash})', $subentry); + } + } + } + + array_push($result, $closeTag, $closeTag); + + /*------------------------------------------------------------------------*/ + + // compile content + $compiling = false; + $result[] = $openTag; + + foreach ($api as $entry) { + // add root entry + $member = $entry->member . $entry->getName(); + $compiling = $compiling ? ($result[] = $closeTag) : true; + + array_push($result, $openTag, '## `' . $member . '`'); + + foreach (array($entry, 'static', 'plugin') as $kind) { + $subentries = is_string($kind) ? $entry->{$kind} : array($kind); + + // title + if ($kind != 'static' && $entry->getType() != 'Object' && + count($subentries) && $subentries[0] != $kind) { + if ($kind == 'plugin') { + $result[] = $closeTag; + } + array_push( + $result, + $openTag, + '## `' . $member . ($kind == 'plugin' ? '.prototype`' : '`') + ); + } + + // body + foreach ($subentries as $subentry) { + // description + array_push( + $result, + $openTag, + Generator::interpolate("### <a id=\"#{hash}\"></a>`#{member}#{separator}#{call}`\n<a href=\"##{hash}\">#</a> [Ⓢ](#{href} \"View in source\") [Ⓣ][1]\n\n#{desc}", $subentry) + ); + + // @param + if (count($params = $subentry->getParams())) { + array_push($result, '', '#### Arguments'); + foreach ($params as $index => $param) { + $result[] = Generator::interpolate('#{num}. `#{name}` (#{type}): #{desc}', array( + 'desc' => $param[2], + 'name' => $param[1], + 'num' => $index + 1, + 'type' => $param[0] + )); + } + } + // @returns + if (count($returns = $subentry->getReturns())) { + array_push( + $result, '', + '#### Returns', + Generator::interpolate('(#{type}): #{desc}', array('desc' => $returns[1], 'type' => $returns[0])) + ); + } + // @example + if ($example = $subentry->getExample()) { + array_push($result, '', '#### Example', $example); + } + array_push($result, "\n* * *", $closeTag); + } + } + } + + // close tags add TOC link reference + array_push($result, $closeTag, $closeTag, '', ' [1]: #' . $toc . ' "Jump back to the TOC."'); + + // cleanup whitespace + return trim(preg_replace('/ +\n/', "\n", join($result, "\n"))); + } +} +?> diff --git a/web/src/vendor/benchmark/vendor/platform.js/LICENSE.txt b/web/src/vendor/benchmark/vendor/platform.js/LICENSE.txt new file mode 100644 index 00000000..dadad22f --- /dev/null +++ b/web/src/vendor/benchmark/vendor/platform.js/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/web/src/vendor/benchmark/vendor/platform.js/README.md b/web/src/vendor/benchmark/vendor/platform.js/README.md new file mode 100644 index 00000000..b9133118 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/platform.js/README.md @@ -0,0 +1,98 @@ +# Platform.js <sup>v1.0.0</sup> + +A platform detection library that works on nearly all JavaScript platforms<sup><a name="fnref1" href="#fn1">1</a></sup>. + +## Disclaimer + +Platform.js is for informational purposes only and **not** intended as a substitution for [feature detection/inference](http://allyoucanleet.com/post/18087210413/feature-testing-costs#screencast2) checks. + +## BestieJS + +Platform.js is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation. + +## Documentation + +The documentation for Platform.js can be viewed here: [/doc/README.md](https://github.com/bestiejs/platform.js/blob/master/doc/README.md#readme) + +For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/platform.js/wiki/Roadmap). + +## Support + +Platform.js has been tested in at least Adobe AIR 3.1, Chrome 5-21, Firefox 1.5-13, IE 6-9, Opera 9.25-12.01, Safari 3-6, Node.js 0.8.6, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC5. + +## Installation and usage + +In a browser or Adobe AIR: + +```html +<script src="platform.js"></script> +``` + +Via [npm](http://npmjs.org/): + +```bash +npm install platform +``` + +In [Node.js](http://nodejs.org/) and [RingoJS](http://ringojs.org/): + +```js +var platform = require('platform'); +``` + +In [Rhino](http://www.mozilla.org/rhino/): + +```js +load('platform.js'); +``` + +In an AMD loader like [RequireJS](http://requirejs.org/): + +```js +require({ + 'paths': { + 'platform': 'path/to/platform' + } +}, +['platform'], function(platform) { + console.log(platform.name); +}); +``` + +Usage example: + +```js +// on IE10 x86 platform preview running in IE7 compatibility mode on Windows 7 64 bit edition +platform.name; // 'IE' +platform.version; // '10.0' +platform.layout; // 'Trident' +platform.os; // 'Windows Server 2008 R2 / 7 x64' +platform.description; // 'IE 10.0 x86 (platform preview; running in IE 7 mode) on Windows Server 2008 R2 / 7 x64' + +// or on an iPad +platform.name; // 'Safari' +platform.version; // '5.1' +platform.product; // 'iPad' +platform.manufacturer; // 'Apple' +platform.layout; // 'WebKit' +platform.os; // 'iOS 5.0' +platform.description; // 'Safari 5.1 on Apple iPad (iOS 5.0)' + +// or parsing a given UA string +var info = platform.parse('Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7.2; en; rv:2.0) Gecko/20100101 Firefox/4.0 Opera 11.52'); +info.name; // 'Opera' +info.version; // '11.52' +info.layout; // 'Presto' +info.os; // 'Mac OS X 10.7.2' +info.description; // 'Opera 11.52 (identifying as Firefox 4.0) on Mac OS X 10.7.2' +``` + +## Author + +* [John-David Dalton](http://allyoucanleet.com/) + [](https://twitter.com/jdalton "Follow @jdalton on Twitter") + +## Contributors + +* [Mathias Bynens](http://mathiasbynens.be/) + [](https://twitter.com/mathias "Follow @mathias on Twitter") diff --git a/web/src/vendor/benchmark/vendor/platform.js/platform.js b/web/src/vendor/benchmark/vendor/platform.js/platform.js new file mode 100644 index 00000000..a8a5482b --- /dev/null +++ b/web/src/vendor/benchmark/vendor/platform.js/platform.js @@ -0,0 +1,996 @@ +/*! + * Platform.js v1.0.0 <http://mths.be/platform> + * Copyright 2010-2012 John-David Dalton <http://allyoucanleet.com/> + * Available under MIT license <http://mths.be/mit> + */ +;(function(window) { + 'use strict'; + + /** Backup possible window/global object */ + var oldWin = window; + + /** Detect free variable `exports` */ + var freeExports = typeof exports == 'object' && exports; + + /** Detect free variable `global` */ + var freeGlobal = typeof global == 'object' && global && + (global == global.global ? (window = global) : global); + + /** Opera regexp */ + var reOpera = /Opera/; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** Detect Java environment */ + var java = /Java/.test(getClassOf(window.java)) && window.java; + + /** A character to represent alpha */ + var alpha = java ? 'a' : '\u03b1'; + + /** A character to represent beta */ + var beta = java ? 'b' : '\u03b2'; + + /** Browser document object */ + var doc = window.document || {}; + + /** Used to check for own properties of an object */ + var hasOwnProperty = {}.hasOwnProperty; + + /** Browser navigator object */ + var nav = window.navigator || {}; + + /** + * Detect Opera browser + * http://www.howtocreate.co.uk/operaStuff/operaObject.html + * http://dev.opera.com/articles/view/opera-mini-web-content-authoring-guidelines/#operamini + */ + var opera = window.operamini || window.opera; + + /** Opera [[Class]] */ + var operaClass = reOpera.test(operaClass = getClassOf(opera)) ? operaClass : (opera = null); + + /** Possible global object */ + var thisBinding = this; + + /** Browser user agent string */ + var userAgent = nav.userAgent || ''; + + /*--------------------------------------------------------------------------*/ + + /** + * Capitalizes a string value. + * + * @private + * @param {String} string The string to capitalize. + * @returns {String} The capitalized string. + */ + function capitalize(string) { + string = String(string); + return string.charAt(0).toUpperCase() + string.slice(1); + } + + /** + * An iteration utility for arrays and objects. + * + * @private + * @param {Array|Object} object The object to iterate over. + * @param {Function} callback The function called per iteration. + */ + function each(object, callback) { + var index = -1, + length = object.length; + + if (length == length >>> 0) { + while (++index < length) { + callback(object[index], index, object); + } + } else { + forOwn(object, callback); + } + } + + /** + * Trim and conditionally capitalize string values. + * + * @private + * @param {String} string The string to format. + * @returns {String} The formatted string. + */ + function format(string) { + string = trim(string); + return /^(?:webOS|i(?:OS|P))/.test(string) + ? string + : capitalize(string); + } + + /** + * Iterates over an object's own properties, executing the `callback` for each. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} callback The function executed per own property. + */ + function forOwn(object, callback) { + for (var key in object) { + hasKey(object, key) && callback(object[key], key, object); + } + } + + /** + * Gets the internal [[Class]] of a value. + * + * @private + * @param {Mixed} value The value. + * @returns {String} The [[Class]]. + */ + function getClassOf(value) { + return value == null + ? capitalize(value) + : toString.call(value).slice(8, -1); + } + + /** + * Checks if an object has the specified key as a direct property. + * + * @private + * @param {Object} object The object to check. + * @param {String} key The key to check for. + * @returns {Boolean} Returns `true` if key is a direct property, else `false`. + */ + function hasKey() { + // lazy define for others (not as accurate) + hasKey = function(object, key) { + var parent = object != null && (object.constructor || Object).prototype; + return !!parent && key in Object(object) && !(key in parent && object[key] === parent[key]); + }; + // for modern browsers + if (getClassOf(hasOwnProperty) == 'Function') { + hasKey = function(object, key) { + return object != null && hasOwnProperty.call(object, key); + }; + } + // for Safari 2 + else if ({}.__proto__ == Object.prototype) { + hasKey = function(object, key) { + var result = false; + if (object != null) { + object = Object(object); + object.__proto__ = [object.__proto__, object.__proto__ = null, result = key in object][0]; + } + return result; + }; + } + return hasKey.apply(this, arguments); + } + + /** + * Host objects can return type values that are different from their actual + * data type. The objects we are concerned with usually return non-primitive + * types of object, function, or unknown. + * + * @private + * @param {Mixed} object The owner of the property. + * @param {String} property The property to check. + * @returns {Boolean} Returns `true` if the property value is a non-primitive, else `false`. + */ + function isHostType(object, property) { + var type = object != null ? typeof object[property] : 'number'; + return !/^(?:boolean|number|string|undefined)$/.test(type) && + (type == 'object' ? !!object[property] : true); + } + + /** + * Prepares a string for use in a RegExp constructor by making hyphens and + * spaces optional. + * + * @private + * @param {String} string The string to qualify. + * @returns {String} The qualified string. + */ + function qualify(string) { + return String(string).replace(/([ -])(?!$)/g, '$1?'); + } + + /** + * A bare-bones` Array#reduce` like utility function. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} accumulator Initial value of the accumulator. + * @returns {Mixed} The accumulator. + */ + function reduce(array, callback) { + var accumulator = null; + each(array, function(value, index) { + accumulator = callback(accumulator, value, index, array); + }); + return accumulator; + } + + /** + * Removes leading and trailing whitespace from a string. + * + * @private + * @param {String} string The string to trim. + * @returns {String} The trimmed string. + */ + function trim(string) { + return String(string).replace(/^ +| +$/g, ''); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a new platform object. + * + * @memberOf platform + * @param {String} [ua = navigator.userAgent] The user agent string. + * @returns {Object} A platform object. + */ + function parse(ua) { + + ua || (ua = userAgent); + + /** Temporary variable used over the script's lifetime */ + var data; + + /** The CPU architecture */ + var arch = ua; + + /** Platform description array */ + var description = []; + + /** Platform alpha/beta indicator */ + var prerelease = null; + + /** A flag to indicate that environment features should be used to resolve the platform */ + var useFeatures = ua == userAgent; + + /** The browser/environment version */ + var version = useFeatures && opera && typeof opera.version == 'function' && opera.version(); + + /* Detectable layout engines (order is important) */ + var layout = getLayout([ + { 'label': 'WebKit', 'pattern': 'AppleWebKit' }, + 'iCab', + 'Presto', + 'NetFront', + 'Tasman', + 'Trident', + 'KHTML', + 'Gecko' + ]); + + /* Detectable browser names (order is important) */ + var name = getName([ + 'Adobe AIR', + 'Arora', + 'Avant Browser', + 'Camino', + 'Epiphany', + 'Fennec', + 'Flock', + 'Galeon', + 'GreenBrowser', + 'iCab', + 'Iceweasel', + 'Iron', + 'K-Meleon', + 'Konqueror', + 'Lunascape', + 'Maxthon', + 'Midori', + 'Nook Browser', + 'PhantomJS', + 'Raven', + 'Rekonq', + 'RockMelt', + 'SeaMonkey', + { 'label': 'Silk', 'pattern': '(?:Cloud9|Silk-Accelerated)' }, + 'Sleipnir', + 'SlimBrowser', + 'Sunrise', + 'Swiftfox', + 'WebPositive', + 'Opera Mini', + 'Opera', + 'Chrome', + { 'label': 'Chrome Mobile', 'pattern': '(?:CriOS|CrMo)' }, + { 'label': 'Firefox', 'pattern': '(?:Firefox|Minefield)' }, + { 'label': 'IE', 'pattern': 'MSIE' }, + 'Safari' + ]); + + /* Detectable products (order is important) */ + var product = getProduct([ + 'BlackBerry', + { 'label': 'Galaxy S', 'pattern': 'GT-I9000' }, + { 'label': 'Galaxy S2', 'pattern': 'GT-I9100' }, + 'Google TV', + 'iPad', + 'iPod', + 'iPhone', + 'Kindle', + { 'label': 'Kindle Fire', 'pattern': '(?:Cloud9|Silk-Accelerated)' }, + 'Nook', + 'PlayBook', + 'PlayStation Vita', + 'TouchPad', + 'Transformer', + 'Xoom' + ]); + + /* Detectable manufacturers */ + var manufacturer = getManufacturer({ + 'Apple': { 'iPad': 1, 'iPhone': 1, 'iPod': 1 }, + 'Amazon': { 'Kindle': 1, 'Kindle Fire': 1 }, + 'Asus': { 'Transformer': 1 }, + 'Barnes & Noble': { 'Nook': 1 }, + 'BlackBerry': { 'PlayBook': 1 }, + 'Google': { 'Google TV': 1 }, + 'HP': { 'TouchPad': 1 }, + 'LG': { }, + 'Motorola': { 'Xoom': 1 }, + 'Nokia': { }, + 'Samsung': { 'Galaxy S': 1, 'Galaxy S2': 1 }, + 'Sony': { 'PlayStation Vita': 1 } + }); + + /* Detectable OSes (order is important) */ + var os = getOS([ + 'Android', + 'CentOS', + 'Debian', + 'Fedora', + 'FreeBSD', + 'Gentoo', + 'Haiku', + 'Kubuntu', + 'Linux Mint', + 'Red Hat', + 'SuSE', + 'Ubuntu', + 'Xubuntu', + 'Cygwin', + 'Symbian OS', + 'hpwOS', + 'webOS ', + 'webOS', + 'Tablet OS', + 'Linux', + 'Mac OS X', + 'Macintosh', + 'Mac', + 'Windows 98;', + 'Windows ' + ]); + + /*------------------------------------------------------------------------*/ + + /** + * Picks the layout engine from an array of guesses. + * + * @private + * @param {Array} guesses An array of guesses. + * @returns {String|Null} The detected layout engine. + */ + function getLayout(guesses) { + return reduce(guesses, function(result, guess) { + return result || RegExp('\\b' + ( + guess.pattern || qualify(guess) + ) + '\\b', 'i').exec(ua) && (guess.label || guess); + }); + } + + /** + * Picks the manufacturer from an array of guesses. + * + * @private + * @param {Array} guesses An array of guesses. + * @returns {String|Null} The detected manufacturer. + */ + function getManufacturer(guesses) { + return reduce(guesses, function(result, value, key) { + // lookup the manufacturer by product or scan the UA for the manufacturer + return result || ( + value[product] || + value[0/*Opera 9.25 fix*/, /^[a-z]+(?: +[a-z]+\b)*/i.exec(product)] || + RegExp('\\b' + (key.pattern || qualify(key)) + '(?:\\b|\\w*\\d)', 'i').exec(ua) + ) && (key.label || key); + }); + } + + /** + * Picks the browser name from an array of guesses. + * + * @private + * @param {Array} guesses An array of guesses. + * @returns {String|Null} The detected browser name. + */ + function getName(guesses) { + return reduce(guesses, function(result, guess) { + return result || RegExp('\\b' + ( + guess.pattern || qualify(guess) + ) + '\\b', 'i').exec(ua) && (guess.label || guess); + }); + } + + /** + * Picks the OS name from an array of guesses. + * + * @private + * @param {Array} guesses An array of guesses. + * @returns {String|Null} The detected OS name. + */ + function getOS(guesses) { + return reduce(guesses, function(result, guess) { + var pattern = guess.pattern || qualify(guess); + if (!result && (result = + RegExp('\\b' + pattern + '(?:/[\\d.]+|[ \\w.]*)', 'i').exec(ua))) { + // platform tokens defined at + // http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx + // http://web.archive.org/web/20081122053950/http://msdn.microsoft.com/en-us/library/ms537503(VS.85).aspx + data = { + '6.2': '8', + '6.1': 'Server 2008 R2 / 7', + '6.0': 'Server 2008 / Vista', + '5.2': 'Server 2003 / XP 64-bit', + '5.1': 'XP', + '5.01': '2000 SP1', + '5.0': '2000', + '4.0': 'NT', + '4.90': 'ME' + }; + // detect Windows version from platform tokens + if (/^Win/i.test(result) && + (data = data[0/*Opera 9.25 fix*/, /[\d.]+$/.exec(result)])) { + result = 'Windows ' + data; + } + // correct character case and cleanup + result = format(String(result) + .replace(RegExp(pattern, 'i'), guess.label || guess) + .replace(/ ce$/i, ' CE') + .replace(/hpw/i, 'web') + .replace(/Macintosh/, 'Mac OS') + .replace(/_PowerPC/i, ' OS') + .replace(/(OS X) [^ \d]+/i, '$1') + .replace(/\/(\d)/, ' $1') + .replace(/_/g, '.') + .replace(/(?: BePC|[ .]*fc[ \d.]+)$/i, '') + .replace(/x86\.64/gi, 'x86_64') + .split(' on ')[0]); + } + return result; + }); + } + + /** + * Picks the product name from an array of guesses. + * + * @private + * @param {Array} guesses An array of guesses. + * @returns {String|Null} The detected product name. + */ + function getProduct(guesses) { + return reduce(guesses, function(result, guess) { + var pattern = guess.pattern || qualify(guess); + if (!result && (result = + RegExp('\\b' + pattern + ' *\\d+[.\\w_]*', 'i').exec(ua) || + RegExp('\\b' + pattern + '(?:; *(?:[a-z]+[_-])?[a-z]+\\d+|[^ ();-]*)', 'i').exec(ua) + )) { + // split by forward slash and append product version if needed + if ((result = String(guess.label || result).split('/'))[1] && !/[\d.]+/.test(result[0])) { + result[0] += ' ' + result[1]; + } + // correct character case and cleanup + guess = guess.label || guess; + result = format(result[0] + .replace(RegExp(pattern, 'i'), guess) + .replace(RegExp('; *(?:' + guess + '[_-])?', 'i'), ' ') + .replace(RegExp('(' + guess + ')(\\w)', 'i'), '$1 $2')); + } + return result; + }); + } + + /** + * Resolves the version using an array of UA patterns. + * + * @private + * @param {Array} patterns An array of UA patterns. + * @returns {String|Null} The detected version. + */ + function getVersion(patterns) { + return reduce(patterns, function(result, pattern) { + return result || (RegExp(pattern + + '(?:-[\\d.]+/|(?: for [\\w-]+)?[ /-])([\\d.]+[^ ();/_-]*)', 'i').exec(ua) || 0)[1] || null; + }); + } + + /*------------------------------------------------------------------------*/ + + /** + * Returns `platform.description` when the platform object is coerced to a string. + * + * @name toString + * @memberOf platform + * @returns {String} Returns `platform.description` if available, else an empty string. + */ + function toStringPlatform() { + return this.description || ''; + } + + /*------------------------------------------------------------------------*/ + + // convert layout to an array so we can add extra details + layout && (layout = [layout]); + + // detect product names that contain their manufacturer's name + if (manufacturer && !product) { + product = getProduct([manufacturer]); + } + // clean up Google TV + if ((data = /Google TV/.exec(product))) { + product = data[0]; + } + // detect simulators + if (/\bSimulator\b/i.test(ua)) { + product = (product ? product + ' ' : '') + 'Simulator'; + } + // detect iOS + if (/^iP/.test(product)) { + name || (name = 'Safari'); + os = 'iOS' + ((data = / OS ([\d_]+)/i.exec(ua)) + ? ' ' + data[1].replace(/_/g, '.') + : ''); + } + // detect Kubuntu + else if (name == 'Konqueror' && !/buntu/i.test(os)) { + os = 'Kubuntu'; + } + // detect Android browsers + else if (manufacturer && manufacturer != 'Google' && + /Chrome|Vita/.test(name + ';' + product)) { + name = 'Android Browser'; + os = /Android/.test(os) ? os : 'Android'; + } + // detect false positives for Firefox/Safari + else if (!name || (data = !/\bMinefield\b/i.test(ua) && /Firefox|Safari/.exec(name))) { + // escape the `/` for Firefox 1 + if (name && !product && /[\/,]|^[^(]+?\)/.test(ua.slice(ua.indexOf(data + '/') + 8))) { + // clear name of false positives + name = null; + } + // reassign a generic name + if ((data = product || manufacturer || os) && + (product || manufacturer || /Android|Symbian OS|Tablet OS|webOS/.test(os))) { + name = /[a-z]+(?: Hat)?/i.exec(/Android/.test(os) ? os : data) + ' Browser'; + } + } + // detect non-Opera versions (order is important) + if (!version) { + version = getVersion([ + '(?:Cloud9|CriOS|CrMo|Opera ?Mini|Raven|Silk(?!/[\\d.]+$))', + 'Version', + qualify(name), + '(?:Firefox|Minefield|NetFront)' + ]); + } + // detect stubborn layout engines + if (layout == 'iCab' && parseFloat(version) > 3) { + layout = ['WebKit']; + } else if (data = + /Opera/.test(name) && 'Presto' || + /\b(?:Midori|Nook|Safari)\b/i.test(ua) && 'WebKit' || + !layout && /\bMSIE\b/i.test(ua) && (/^Mac/.test(os) ? 'Tasman' : 'Trident')) { + layout = [data]; + } + // leverage environment features + if (useFeatures) { + // detect server-side environments + // Rhino has a global function while others have a global object + if (isHostType(window, 'global')) { + if (java) { + data = java.lang.System; + arch = data.getProperty('os.arch'); + os = os || data.getProperty('os.name') + ' ' + data.getProperty('os.version'); + } + if (typeof exports == 'object' && exports) { + // if `thisBinding` is the [ModuleScope] + if (thisBinding == oldWin && typeof system == 'object' && (data = [system])[0]) { + os || (os = data[0].os || null); + try { + data[1] = require('ringo/engine').version; + version = data[1].join('.'); + name = 'RingoJS'; + } catch(e) { + if (data[0].global == freeGlobal) { + name = 'Narwhal'; + } + } + } else if (typeof process == 'object' && (data = process)) { + name = 'Node.js'; + arch = data.arch; + os = data.platform; + version = /[\d.]+/.exec(data.version)[0]; + } + } else if (getClassOf(window.environment) == 'Environment') { + name = 'Rhino'; + } + } + // detect Adobe AIR + else if (getClassOf(data = window.runtime) == 'ScriptBridgingProxyObject') { + name = 'Adobe AIR'; + os = data.flash.system.Capabilities.os; + } + // detect PhantomJS + else if (getClassOf(data = window.phantom) == 'RuntimeObject') { + name = 'PhantomJS'; + version = (data = data.version || null) && (data.major + '.' + data.minor + '.' + data.patch); + } + // detect IE compatibility modes + else if (typeof doc.documentMode == 'number' && (data = /\bTrident\/(\d+)/i.exec(ua))) { + // we're in compatibility mode when the Trident version + 4 doesn't + // equal the document mode + version = [version, doc.documentMode]; + if ((data = +data[1] + 4) != version[1]) { + description.push('IE ' + version[1] + ' mode'); + layout[1] = ''; + version[1] = data; + } + version = name == 'IE' ? String(version[1].toFixed(1)) : version[0]; + } + os = os && format(os); + } + // detect prerelease phases + if (version && (data = + /(?:[ab]|dp|pre|[ab]\d+pre)(?:\d+\+?)?$/i.exec(version) || + /(?:alpha|beta)(?: ?\d)?/i.exec(ua + ';' + (useFeatures && nav.appMinorVersion)) || + /\bMinefield\b/i.test(ua) && 'a')) { + prerelease = /b/i.test(data) ? 'beta' : 'alpha'; + version = version.replace(RegExp(data + '\\+?$'), '') + + (prerelease == 'beta' ? beta : alpha) + (/\d+\+?/.exec(data) || ''); + } + // rename code name "Fennec" + if (name == 'Fennec') { + name = 'Firefox Mobile'; + } + // obscure Maxthon's unreliable version + else if (name == 'Maxthon' && version) { + version = version.replace(/\.[\d.]+/, '.x'); + } + // detect Silk desktop/accelerated modes + else if (name == 'Silk') { + if (!/Mobi/i.test(ua)) { + os = 'Android'; + description.unshift('desktop mode'); + } + if (/Accelerated *= *true/i.test(ua)) { + description.unshift('accelerated'); + } + } + // detect Windows Phone desktop mode + else if (name == 'IE' && (data = (/; *(?:XBLWP|ZuneWP)(\d+)/i.exec(ua) || 0)[1])) { + name += ' Mobile'; + os = 'Windows Phone OS ' + data + '.x'; + description.unshift('desktop mode'); + } + // add mobile postfix + else if ((name == 'IE' || name && !product && !/Browser|Mobi/.test(name)) && + (os == 'Windows CE' || /Mobi/i.test(ua))) { + name += ' Mobile'; + } + // detect IE platform preview + else if (name == 'IE' && useFeatures && typeof external == 'object' && !external) { + description.unshift('platform preview'); + } + // detect BlackBerry OS version + // http://docs.blackberry.com/en/developers/deliverables/18169/HTTP_headers_sent_by_BB_Browser_1234911_11.jsp + else if (/BlackBerry/.test(product) && (data = + (RegExp(product.replace(/ +/g, ' *') + '/([.\\d]+)', 'i').exec(ua) || 0)[1] || + version)) { + os = 'Device Software ' + data; + version = null; + } + // detect Opera identifying/masking itself as another browser + // http://www.opera.com/support/kb/view/843/ + else if (this != forOwn && ( + (useFeatures && opera) || + (/Opera/.test(name) && /\b(?:MSIE|Firefox)\b/i.test(ua)) || + (name == 'Firefox' && /OS X (?:\d+\.){2,}/.test(os)) || + (name == 'IE' && ( + (os && !/^Win/.test(os) && version > 5.5) || + /Windows XP/.test(os) && version > 8 || + version == 8 && !/Trident/.test(ua) + )) + ) && !reOpera.test(data = parse.call(forOwn, ua.replace(reOpera, '') + ';')) && data.name) { + + // when "indentifying", the UA contains both Opera and the other browser's name + data = 'ing as ' + data.name + ((data = data.version) ? ' ' + data : ''); + if (reOpera.test(name)) { + if (/IE/.test(data) && os == 'Mac OS') { + os = null; + } + data = 'identify' + data; + } + // when "masking", the UA contains only the other browser's name + else { + data = 'mask' + data; + if (operaClass) { + name = format(operaClass.replace(/([a-z])([A-Z])/g, '$1 $2')); + } else { + name = 'Opera'; + } + if (/IE/.test(data)) { + os = null; + } + if (!useFeatures) { + version = null; + } + } + layout = ['Presto']; + description.push(data); + } + // detect WebKit Nightly and approximate Chrome/Safari versions + if ((data = (/\bAppleWebKit\/([\d.]+\+?)/i.exec(ua) || 0)[1])) { + // correct build for numeric comparison + // (e.g. "532.5" becomes "532.05") + data = [parseFloat(data.replace(/\.(\d)$/, '.0$1')), data]; + // nightly builds are postfixed with a `+` + if (name == 'Safari' && data[1].slice(-1) == '+') { + name = 'WebKit Nightly'; + prerelease = 'alpha'; + version = data[1].slice(0, -1); + } + // clear incorrect browser versions + else if (version == data[1] || + version == (/\bSafari\/([\d.]+\+?)/i.exec(ua) || 0)[1]) { + version = null; + } + // use the full Chrome version when available + data = [data[0], (/\bChrome\/([\d.]+)/i.exec(ua) || 0)[1]]; + + // detect JavaScriptCore + // http://stackoverflow.com/questions/6768474/how-can-i-detect-which-javascript-engine-v8-or-jsc-is-used-at-runtime-in-androi + if (!useFeatures || (/internal|\n/i.test(toString.toString()) && !data[1])) { + layout[1] = 'like Safari'; + data = (data = data[0], data < 400 ? 1 : data < 500 ? 2 : data < 526 ? 3 : data < 533 ? 4 : data < 534 ? '4+' : data < 535 ? 5 : '5'); + } else { + layout[1] = 'like Chrome'; + data = data[1] || (data = data[0], data < 530 ? 1 : data < 532 ? 2 : data < 532.05 ? 3 : data < 533 ? 4 : data < 534.03 ? 5 : data < 534.07 ? 6 : data < 534.10 ? 7 : data < 534.13 ? 8 : data < 534.16 ? 9 : data < 534.24 ? 10 : data < 534.30 ? 11 : data < 535.01 ? 12 : data < 535.02 ? '13+' : data < 535.07 ? 15 : data < 535.11 ? 16 : data < 535.19 ? 17 : data < 536.05 ? 18 : data < 536.10 ? 19 : data < 537.01 ? 20 : '21'); + } + // add the postfix of ".x" or "+" for approximate versions + layout[1] += ' ' + (data += typeof data == 'number' ? '.x' : /[.+]/.test(data) ? '' : '+'); + // obscure version for some Safari 1-2 releases + if (name == 'Safari' && (!version || parseInt(version) > 45)) { + version = data; + } + } + // detect Opera desktop modes + if (name == 'Opera' && (data = /(?:zbov|zvav)$/.exec(os))) { + name += ' '; + description.unshift('desktop mode'); + if (data == 'zvav') { + name += 'Mini'; + version = null; + } else { + name += 'Mobile'; + } + } + // detect Chrome desktop mode + else if (name == 'Safari' && /Chrome/.exec(layout[1])) { + description.unshift('desktop mode'); + name = 'Chrome Mobile'; + version = null; + + if (/Mac OS X/.test(os)) { + manufacturer = 'Apple'; + os = 'iOS 4.3+'; + } else { + os = null; + } + } + // strip incorrect OS versions + if (version && version.indexOf(data = /[\d.]+$/.exec(os)) == 0 && + ua.indexOf('/' + data + '-') > -1) { + os = trim(os.replace(data, '')); + } + // add layout engine + if (layout && !/Avant|Nook/.test(name) && ( + /Browser|Lunascape|Maxthon/.test(name) || + /^(?:Adobe|Arora|Midori|Phantom|Rekonq|Rock|Sleipnir|Web)/.test(name) && layout[1])) { + // don't add layout details to description if they are falsey + (data = layout[layout.length - 1]) && description.push(data); + } + // combine contextual information + if (description.length) { + description = ['(' + description.join('; ') + ')']; + } + // append manufacturer + if (manufacturer && product && product.indexOf(manufacturer) < 0) { + description.push('on ' + manufacturer); + } + // append product + if (product) { + description.push((/^on /.test(description[description.length -1]) ? '' : 'on ') + product); + } + // parse OS into an object + if (os) { + data = / ([\d.+]+)$/.exec(os); + os = { + 'architecture': 32, + 'family': data ? os.replace(data[0], '') : os, + 'version': data ? data[1] : null, + 'toString': function() { + var version = this.version; + return this.family + (version ? ' ' + version : '') + (this.architecture == 64 ? ' 64-bit' : ''); + } + }; + } + // add browser/OS architecture + if ((data = / (?:AMD|IA|Win|WOW|x86_|x)64\b/i.exec(arch)) && !/\bi686\b/i.test(arch)) { + if (os) { + os.architecture = 64; + os.family = os.family.replace(data, ''); + } + if (name && (/WOW64/i.test(ua) || + (useFeatures && /\w(?:86|32)$/.test(nav.cpuClass || nav.platform)))) { + description.unshift('32-bit'); + } + } + + ua || (ua = null); + + /*------------------------------------------------------------------------*/ + + /** + * The platform object. + * + * @name platform + * @type Object + */ + return { + + /** + * The browser/environment version. + * + * @memberOf platform + * @type String|Null + */ + 'version': name && version && (description.unshift(version), version), + + /** + * The name of the browser/environment. + * + * @memberOf platform + * @type String|Null + */ + 'name': name && (description.unshift(name), name), + + /** + * The name of the operating system. + * + * @memberOf platform + * @type Object + */ + 'os': os + ? (name && + !(os == String(os).split(' ')[0] && (os == name.split(' ')[0] || product)) && + description.push(product ? '(' + os + ')' : 'on ' + os), os) + : { + + /** + * The CPU architecture the OS is built for. + * + * @memberOf platform.os + * @type String|Null + */ + 'architecture': null, + + /** + * The family of the OS. + * + * @memberOf platform.os + * @type String|Null + */ + 'family': null, + + /** + * The version of the OS. + * + * @memberOf platform.os + * @type String|Null + */ + 'version': null, + + /** + * Returns the OS string. + * + * @memberOf platform.os + * @returns {String} The OS string. + */ + 'toString': function() { return 'null'; } + }, + + /** + * The platform description. + * + * @memberOf platform + * @type String|Null + */ + 'description': description.length ? description.join(' ') : ua, + + /** + * The name of the browser layout engine. + * + * @memberOf platform + * @type String|Null + */ + 'layout': layout && layout[0], + + /** + * The name of the product's manufacturer. + * + * @memberOf platform + * @type String|Null + */ + 'manufacturer': manufacturer, + + /** + * The alpha/beta release indicator. + * + * @memberOf platform + * @type String|Null + */ + 'prerelease': prerelease, + + /** + * The name of the product hosting the browser. + * + * @memberOf platform + * @type String|Null + */ + 'product': product, + + /** + * The browser's user agent string. + * + * @memberOf platform + * @type String|Null + */ + 'ua': ua, + + // parses a user agent string into a platform object + 'parse': parse, + + // returns the platform description + 'toString': toStringPlatform + }; + } + + /*--------------------------------------------------------------------------*/ + + // expose platform + // some AMD build optimizers, like r.js, check for specific condition patterns like the following: + if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { + // define as an anonymous module so, through path mapping, it can be aliased + define(function() { + return parse(); + }); + } + // check for `exports` after `define` in case a build optimizer adds an `exports` object + else if (freeExports) { + // in Narwhal, Node.js, or RingoJS + forOwn(parse(), function(value, key) { + freeExports[key] = value; + }); + } + // in a browser or Rhino + else { + // use square bracket notation so Closure Compiler won't munge `platform` + // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export + window['platform'] = parse(); + } +}(this)); diff --git a/web/src/vendor/benchmark/vendor/qunit-clib/LICENSE.txt b/web/src/vendor/benchmark/vendor/qunit-clib/LICENSE.txt new file mode 100644 index 00000000..dadad22f --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit-clib/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/> + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file diff --git a/web/src/vendor/benchmark/vendor/qunit-clib/README.md b/web/src/vendor/benchmark/vendor/qunit-clib/README.md new file mode 100644 index 00000000..b84a21c9 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit-clib/README.md @@ -0,0 +1,57 @@ +# QUnit CLIB <sup>v1.0.0</sup> +## command-line interface boilerplate + +QUnit CLIB helps extend QUnit's CLI support to many common CLI environments. + +## Screenshot + + + +## Support + +QUnit CLIB has been tested in at least Node.js 0.4.8-0.8.6, Narwhal v0.3.2, RingoJS v0.8.0, and Rhino v1.7RC3-RC5. + +## Usage + +```js +(function(window) { + + // use a single load function + var load = typeof require == 'function' ? require : window.load; + + // load QUnit and CLIB if needed + var QUnit = + window.QUnit || ( + window.setTimeout || (window.addEventListener = window.setTimeout = / /), + window.QUnit = load('path/to/qunit.js') || window.QUnit, + load('path/to/qunit-clib.js'), + (window.addEventListener || 0).test && delete window.addEventListener, + window.QUnit + ); + + // explicitly call `QUnit.module()` instead of `module()` + // in case we are in a CLI environment + QUnit.module('A Test Module'); + + test('A Test', function() { + // ... + }); + + // must call `QUnit.start()` if using QUnit < 1.3.0 with Node.js or any + // version of QUnit with Narwhal, Rhino, or RingoJS + if (!window.document) { + QUnit.start(); + } +}(typeof global == 'object' && global || this)); +``` + +## Footnotes + + 1. QUnit v1.3.0 does not work with Narwhal or Ringo < v0.8.0 + + 2. Rhino v1.7RC4 does not support timeout fallbacks `clearTimeout` and `setTimeout` + +## Author + +* [John-David Dalton](http://allyoucanleet.com/) + [](https://twitter.com/jdalton "Follow @jdalton on Twitter") diff --git a/web/src/vendor/benchmark/vendor/qunit-clib/qunit-clib.js b/web/src/vendor/benchmark/vendor/qunit-clib/qunit-clib.js new file mode 100644 index 00000000..e487c03e --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit-clib/qunit-clib.js @@ -0,0 +1,319 @@ +/*! + * QUnit CLI Boilerplate v1.0.0 + * Copyright 2011-2012 John-David Dalton <http://allyoucanleet.com/> + * Based on a gist by Jörn Zaefferer <https://gist.github.com/722381> + * Available under MIT license <http://mths.be/mit> + */ +;(function(global) { + 'use strict'; + + /** Add `console.log()` support for Narwhal, Rhino, and RingoJS */ + global.console || (global.console = { 'log': global.print }); + + /** Reduce global.QUnit.QUnit -> global.QUnit */ + global.QUnit && (QUnit = QUnit.QUnit || QUnit); + + /*--------------------------------------------------------------------------*/ + + /** Used as a horizontal rule in console output */ + var hr = '----------------------------------------'; + + /** Shortcut used to convert array-like objects to arrays */ + var slice = [].slice; + + /** Used to resolve a value's internal [[Class]] */ + var toString = {}.toString; + + /** Used by timer methods */ + var doneCalled, + timer, + counter = 0, + ids = {}; + + /*--------------------------------------------------------------------------*/ + + /** + * An iteration utility for arrays. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} callback The function called per iteration. + */ + function each(array, callback) { + var index = -1, + length = array.length; + + while (++index < length) { + callback(array[index], index, array); + } + } + + /** + * Checks if the specified `value` is a function. + * + * @private + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if `value` is a function, else `false`. + */ + function isFunction(value) { + return toString.call(value) == '[object Function]'; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Timeout fallbacks based on the work of Andrea Giammarchi and Weston C. + * https://github.com/WebReflection/wru/blob/master/src/rhinoTimers.js + * http://stackoverflow.com/questions/2261705/how-to-run-a-javascript-function-asynchronously-without-using-settimeout + */ + + /** + * Clears the delay set by `setInterval` or `setTimeout`. + * + * @memberOf global + * @param {Number} id The ID of the timeout to be cleared. + */ + function clearTimer(id) { + if (ids[id]) { + ids[id].cancel(); + timer.purge(); + delete ids[id]; + } + } + + /** + * Schedules timer-based callbacks. + * + * @private + * @param {Function} fn The function to call. + * @oaram {Number} delay The number of milliseconds to delay the `fn` call. + * @param [arg1, arg2, ...] Arguments to invoke `fn` with. + * @param {Boolean} repeated A flag to specify whether `fn` is called repeatedly. + * @returns {Number} The the ID of the timeout. + */ + function schedule(fn, delay, args, repeated) { + // Rhino 1.7RC4 will error assigning `task` below + // https://bugzilla.mozilla.org/show_bug.cgi?id=775566 + var task = ids[++counter] = new JavaAdapter(java.util.TimerTask, { + 'run': function() { + fn.apply(global, args); + } + }); + // support non-functions + if (!isFunction(fn)) { + fn = (function(code) { + code = String(code); + return function() { eval(code); }; + }(fn)); + } + // used by setInterval + if (repeated) { + timer.schedule(task, delay, delay); + } + // used by setTimeout + else { + timer.schedule(task, delay); + } + return counter; + } + + /** + * Executes a code snippet or function repeatedly, with a delay between each call. + * + * @memberOf global + * @param {Function|String} fn The function to call or string to evaluate. + * @oaram {Number} delay The number of milliseconds to delay each `fn` call. + * @param [arg1, arg2, ...] Arguments to invoke `fn` with. + * @returns {Number} The the ID of the timeout. + */ + function setInterval(fn, delay) { + return schedule(fn, delay, slice.call(arguments, 2), true); + } + + /** + * Executes a code snippet or a function after specified delay. + * + * @memberOf global + * @param {Function|String} fn The function to call or string to evaluate. + * @oaram {Number} delay The number of milliseconds to delay the `fn` call. + * @param [arg1, arg2, ...] Arguments to invoke `fn` with. + * @returns {Number} The the ID of the timeout. + */ + function setTimeout(fn, delay) { + return schedule(fn, delay, slice.call(arguments, 2)); + } + + /*--------------------------------------------------------------------------*/ + + /** + * A logging callback triggered when all testing is completed. + * + * @memberOf QUnit + * @param {Object} details An object with properties `failed`, `passed`, + * `runtime`, and `total`. + */ + function done(details) { + // stop `asyncTest()` from erroneously calling `done()` twice in + // environments w/o timeouts + if (doneCalled) { + return; + } + doneCalled = true; + console.log(hr); + console.log(' PASS: ' + details.passed + ' FAIL: ' + details.failed + ' TOTAL: ' + details.total); + console.log(' Finished in ' + details.runtime + ' milliseconds.'); + console.log(hr); + + // exit out of Rhino + try { + quit(); + } catch(e) { } + + // exit out of Node.js + try { + process.exit(); + } catch(e) { } + } + + /** + * A logging callback triggered after every assertion. + * + * @memberOf QUnit + * @param {Object} details An object with properties `actual`, `expected`, + * `message`, and `result`. + */ + function log(details) { + var expected = details.expected, + result = details.result, + type = typeof expected != 'undefined' ? 'EQ' : 'OK'; + + var assertion = [ + result ? 'PASS' : 'FAIL', + type, + details.message || 'ok' + ]; + + if (!result && type == 'EQ') { + assertion.push('Expected: ' + expected + ', Actual: ' + details.actual); + } + QUnit.config.testStats.assertions.push(assertion.join(' | ')); + } + + /** + * A logging callback triggered at the start of every test module. + * + * @memberOf QUnit + * @param {Object} details An object with property `name`. + */ + function moduleStart(details) { + console.log(hr); + console.log(details.name); + console.log(hr); + } + + /** + * Converts an object into a string representation. + * + * @memberOf QUnit + * @type Function + * @param {Object} object The object to stringify. + * @returns {String} The result string. + */ + var parseObject = (function() { + var func = QUnit.jsDump.parsers.object; + return function(object) { + // fork to support Rhino's error objects + if (typeof object.rhinoException == 'object') { + return object.name + + ' { message: "' + object.message + + '", fileName: "' + object.fileName + + '", lineNumber: ' + object.lineNumber + ' }'; + } + return func(object); + }; + }()); + + /** + * A logging callback triggered after a test is completed. + * + * @memberOf QUnit + * @param {Object} details An object with properties `failed`, `name`, + * `passed`, and `total`. + */ + function testDone(details) { + var assertions = QUnit.config.testStats.assertions, + testName = details.name; + + if (details.failed > 0) { + console.log(' FAIL - '+ testName); + each(assertions, function(value) { + console.log(' ' + value); + }); + } + else { + console.log(' PASS - ' + testName); + } + assertions.length = 0; + } + + /*--------------------------------------------------------------------------*/ + + /** + * An object used to hold information about the current running test. + * + * @memberOf QUnit.config + * @type Object + */ + QUnit.config.testStats = { + + /** + * An array of test summaries (pipe separated). + * + * @memberOf QUnit.config.testStats + * @type Array + */ + 'assertions': [] + }; + + // add shortcuts to the global + // exclude `module` because some environments have it as a built-in object + each(['asyncTest', 'deepEqual', 'equal', 'equals', 'expect', 'notDeepEqual', + 'notEqual', 'notStrictEqual', 'ok', 'raises', 'same', 'start', 'stop', + 'strictEqual', 'test', 'throws'], function(funcName) { + var func = QUnit[funcName]; + if (func) { + global[funcName] = func; + } + }); + + // expose timer methods to global + try { + timer = new java.util.Timer; + if (!isFunction(global.clearInterval)) { + global.clearInterval = clearTimer; + } + if (!isFunction(global.clearTimeout)) { + global.clearTimeout = clearTimer; + } + if (!isFunction(global.setInterval)) { + global.setInterval = setInterval; + } + if (!isFunction(global.setTimeout)) { + global.setTimeout = setTimeout; + } + } catch(e) { } + + // add callbacks + QUnit.done(done); + QUnit.log(log); + QUnit.moduleStart(moduleStart); + QUnit.testDone(testDone); + + // add wrapped function + QUnit.jsDump.parsers.object = parseObject; + + // must call `QUnit.start()` in the test file if using QUnit < 1.3.0 with + // Node.js or any version of QUnit with Narwhal, Rhino, or RingoJS + QUnit.init(); + +}(typeof global == 'object' && global || this)); diff --git a/web/src/vendor/benchmark/vendor/qunit/README.md b/web/src/vendor/benchmark/vendor/qunit/README.md new file mode 100644 index 00000000..3778a27b --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit/README.md @@ -0,0 +1,49 @@ +[QUnit](http://docs.jquery.com/QUnit) - A JavaScript Unit Testing framework. +================================ + +QUnit is a powerful, easy-to-use, JavaScript test suite. It's used by the jQuery +project to test its code and plugins but is capable of testing any generic +JavaScript code (and even capable of testing JavaScript code on the server-side). + +QUnit is especially useful for regression testing: Whenever a bug is reported, +write a test that asserts the existence of that particular bug. Then fix it and +commit both. Every time you work on the code again, run the tests. If the bug +comes up again - a regression - you'll spot it immediately and know how to fix +it, because you know what code you just changed. + +Having good unit test coverage makes safe refactoring easy and cheap. You can +run the tests after each small refactoring step and always know what change +broke something. + +QUnit is similar to other unit testing frameworks like JUnit, but makes use of +the features JavaScript provides and helps with testing code in the browser, e.g. +with its stop/start facilities for testing asynchronous code. + +If you are interested in helping developing QUnit, you are in the right place. +For related discussions, visit the +[QUnit and Testing forum](http://forum.jquery.com/qunit-and-testing). + +Planning for a qunitjs.com site and other testing tools related work now happens +on the [jQuery Testing Team planning wiki](http://jquerytesting.pbworks.com/w/page/41556026/FrontPage). + +Development +----------- + +To submit patches, fork the repository, create a branch for the change. Then implement +the change, run `grunt` to lint and test it, then commit, push and create a pull request. + +Include some background for the change in the commit message and `Fixes #nnn`, referring +to the issue number you're addressing. + +To run `grunt`, you need `node` and `npm`, then `npm install grunt -g`. + +Releases +-------- + +Install git-extras and run `git changelog` to update History.md. +Update qunit/qunit.js|css and package.json to the release version, commit and +tag, update them again to the next version, commit and push commits and tags +(`git push --tags origin master`). + +Put the 'v' in front of the tag, e.g. `v1.8.0`. Clean up the changelog, removing merge commits +or whitespace cleanups. diff --git a/web/src/vendor/benchmark/vendor/qunit/qunit/qunit-1.8.0.js b/web/src/vendor/benchmark/vendor/qunit/qunit/qunit-1.8.0.js new file mode 100644 index 00000000..c1570c25 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit/qunit/qunit-1.8.0.js @@ -0,0 +1,1863 @@ +/** + * QUnit v1.8.0 - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2012 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +(function( window ) { + +var QUnit, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) +}; + +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} + +Test.count = 0; + +Test.prototype = { + init: function() { + var a, b, li, + tests = id( "qunit-tests" ); + + if ( tests ) { + b = document.createElement( "strong" ); + b.innerHTML = this.name; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); + + li = document.createElement( "li" ); + li.appendChild( b ); + li.appendChild( a ); + li.className = "running"; + li.id = this.id = "qunit-test-output" + testId++; + + tests.appendChild( li ); + } + }, + setup: function() { + if ( this.module !== config.previousModule ) { + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } else if ( config.autorun ) { + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } + + config.current = this; + + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment ); + + runLoggingCallbacks( "testStart", QUnit, { + name: this.testName, + module: this.module + }); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + if ( !config.pollution ) { + saveGlobal(); + } + if ( config.notrycatch ) { + this.testEnvironment.setup.call( this.testEnvironment ); + return; + } + try { + this.testEnvironment.setup.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); + } + }, + run: function() { + config.current = this; + + var running = id( "qunit-testresult" ); + + if ( running ) { + running.innerHTML = "Running: <br/>" + this.name; + } + + if ( this.async ) { + QUnit.stop(); + } + + if ( config.notrycatch ) { + this.callback.call( this.testEnvironment, QUnit.assert ); + return; + } + + try { + this.callback.call( this.testEnvironment, QUnit.assert ); + } catch( e ) { + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + if ( config.notrycatch ) { + this.testEnvironment.teardown.call( this.testEnvironment ); + return; + } else { + try { + this.testEnvironment.teardown.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); + } + } + checkPollution(); + }, + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected == null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected != null && this.expected != this.assertions.length ) { + QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); + } else if ( this.expected == null && !this.assertions.length ) { + QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); + } + + var assertion, a, b, i, li, ol, + test = this, + good = 0, + bad = 0, + tests = id( "qunit-tests" ); + + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + ol = document.createElement( "ol" ); + + for ( i = 0; i < this.assertions.length; i++ ) { + assertion = this.assertions[i]; + + li = document.createElement( "li" ); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); + } + } + + if ( bad === 0 ) { + ol.style.display = "none"; + } + + // `b` initialized at top of scope + b = document.createElement( "strong" ); + b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>"; + + addEvent(b, "click", function() { + var next = b.nextSibling.nextSibling, + display = next.style.display; + next.style.display = display === "none" ? "block" : "none"; + }); + + addEvent(b, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild ( a ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + config.currentModule = name; + config.currentModuleTestEnviroment = testEnvironment; + }, + + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>"; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + if ( config.currentModule ) { + name = "<span class='module-name'>" + config.currentModule + "</span>: " + name; + } + + test = new Test({ + name: name, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnviroment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { + return; + } + + test.queue(); + }, + + // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + config.current.expected = asserts; + }, + + start: function( count ) { + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// Asssert helpers +// All of these must call either QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +QUnit.assert = { + /** + * Asserts rough true-ish result. + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + + var source, + details = { + result: result, + message: msg + }; + + msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); + msg = "<span class='test-message'>" + msg + "</span>"; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + QUnit.push( expected == actual, actual, expected, message ); + }, + + notEqual: function( actual, expected, message ) { + QUnit.push( expected != actual, actual, expected, message ); + }, + + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + raises: function( block, expected, message ) { + var actual, + ok = false; + + if ( typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( actual ); + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + ok = true; + } + } + + QUnit.push( ok, actual, null, message ); + } +}; + +// @deprecated: Kept assertion helpers in root for backwards compatibility +extend( QUnit, QUnit.assert ); + +/** + * @deprecated: Kept for backwards compatibility + * next step: remove entirely + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// We want access to the constructor's prototype +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + urlConfig: [ "noglobals", "notrycatch" ], + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) +if ( typeof exports === "undefined" ) { + extend( window, QUnit ); + + // Expose QUnit object + window.QUnit = QUnit; +} + +// Extend QUnit object, +// these after set here because they should not be exposed as global functions +extend( QUnit, { + config: config, + + // Initialize the configuration options + init: function() { + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date(), + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 0 + }); + + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" + + "<h2 id='qunit-banner'></h2>" + + "<div id='qunit-testrunner-toolbar'></div>" + + "<h2 id='qunit-userAgent'></h2>" + + "<ol id='qunit-tests'></ol>"; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...<br/> "; + } + }, + + // Resets the test setup. Useful for tests that modify the DOM. + // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. + reset: function() { + var fixture; + + if ( window.jQuery ) { + jQuery( "#qunit-fixture" ).html( config.fixture ); + } else { + fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + } + }, + + // Trigger an event on an element. + // @example triggerEvent( document.body, "click" ); + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type ); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) == type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + // consider: typeof null === object + } + if ( obj === null ) { + return "null"; + } + + var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); + message = "<span class='test-message'>" + message + "</span>"; + output = message; + + if ( !result ) { + expected = escapeInnerText( QUnit.jsDump.parse(expected) ); + actual = escapeInnerText( QUnit.jsDump.parse(actual) ); + output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>"; + + if ( actual != expected ) { + output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>"; + output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>"; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; + } + + output += "</table>"; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + result: false, + message: message + }; + + message = escapeInnerText(message ) || "error"; + message = "<span class='test-message'>" + message + "</span>"; + output = message; + + if ( source ) { + details.source = source; + output += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( !hasOwn.call( params, key ) ) { + continue; + } + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent + // load, equiv, jsDump, diff: Attached later +}); + +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + + // Initialize the config, saving the execution queue + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, + urlConfigHtml = "", + oldconfig = extend( {}, config ); + + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + config[val] = QUnit.urlParams[val]; + urlConfigHtml += "<label><input name='" + val + "' type='checkbox'" + ( config[val] ? " checked='checked'" : "" ) + ">" + val + "</label>"; + } + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined }) + "'>" + banner.innerHTML + "</a> " + urlConfigHtml; + addEvent( banner, "change", function( event ) { + var params = {}; + params[ event.target.name ] = event.target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); + if ( toolbar ) { + // `filter` initialized at top of scope + filter = document.createElement( "input" ); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + + addEvent( filter, "click", function() { + var tmp, + ol = document.getElementById( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); + } + } + }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = document.getElementById( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + } + + // `main` initialized at top of scope + main = id( "qunit-fixture" ); + if ( main ) { + config.fixture = main.innerHTML; + } + + if ( config.autostart ) { + QUnit.start(); + } +}; + +addEvent( window, "load", QUnit.load ); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will surpress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not surpressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }); + } + return false; + } + + return ret; +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.<br/>", + "<span class='passed'>", + passed, + "</span> tests of <span class='total'>", + config.stats.all, + "</span> passed, <span class='failed'>", + config.stats.bad, + "</span> failed." + ].join( "" ); + + if ( banner ) { + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module, + fullName = (test.module + ": " + test.testName).toLowerCase(); + + if ( config.testNumber ) { + return test.testNumber === config.testNumber; + } + + if ( module && test.module !== module ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; +} + +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i, regex; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) != -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +function escapeInnerText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + return s.replace( /[\&<>]/g, function( s ) { + switch( s ) { + case "&": return "&"; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + window.setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } +} + +function checkPollution( name ) { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b ) { + for ( var prop in b ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + + // Avoid "Member not found" error in IE8 caused by setting window.constructor + } else if ( prop !== "constructor" || a !== window ) { + a[ prop ] = b[ prop ]; + } + } + + return a; +} + +function addEvent( elem, type, fn ) { + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, fn ); + } else { + fn(); + } +} + +function id( name ) { + return !!( typeof document !== "undefined" && document && document.getElementById ) && + document.getElementById( name ); +} + +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + //debugger; + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé <prathe@gmail.com> +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotaion VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + // the regex itself + a.source === b.source && + // and its modifers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + loop = true;// dont rewalk array + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + return false; + } + } + parents.pop(); + return true; + }, + + "object": function( b, a ) { + var i, j, loop, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + // track reference to avoid circular references + parents.push( a ); + + for ( i in a ) { // be strict: don't ensures hasOwnProperty + // and go deep + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + // don't go down the same path twice + loop = true; + } + } + aProperties.push(i); // collect a's properties + + if (!loop && !innerEquiv( a[i], b[i] ) ) { + eq = false; + break; + } + } + + callers.pop(); // unstack, we are done + parents.pop(); + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType(a) !== QUnit.objectType(b) ) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); + }; + + return innerEquiv; +}()); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + jsDump = { + parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack != -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + //else + if ( type == "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + // else + return ( type == "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj) ) { + type = "date"; + } else if ( QUnit.is( "function", obj) ) { + type = "function"; + } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; + }, + indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this._depth_ + (extra||0) ).join(chr); + }, + up: function( a ) { + this._depth_ += a || 1; + }, + down: function( a ) { + this._depth_ -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: "[ERROR]", //when no parser is found, shouldn"t happen + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + if ( Object.keys ) { + keys = Object.keys( map ); + } else { + keys = []; + for ( key in map ) { + keys.push( key ); + } + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var a, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for ( a in QUnit.jsDump.DOMAttrs ) { + val = node[ QUnit.jsDump.DOMAttrs[a] ]; + if ( val ) { + ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + return ret + close + open + "/" + tag + close; + }, + functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + args[l] = String.fromCharCode(97+l);//97 is 'a' + } + return " " + args.join( ", " ) + " "; + }, + key: quote, //object calls it internally, the key part of an item in a map + functionCode: "[code]", //function calls it internally, it's the content of the function + attribute: quote, //node calls it internally, it's an html attribute value + string: quote, + date: quote, + regexp: literal, //regex + number: literal, + "boolean": literal + }, + DOMAttrs: { + //attributes to dump from nodes, name=>realName + id: "id", + name: "name", + "class": "className" + }, + HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) + indentChar: " ",//indentation unit + multiline: true //if true, items in a collection, are separated by a \n, else just a space. + }; + + return jsDump; +}()); + +// from Sizzle.js +function getText( elems ) { + var i, elem, + ret = ""; + + for ( i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +} + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over" + */ +QUnit.diff = (function() { + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( ns[ n[i] ] == null ) { + ns[ n[i] ] = { + rows: [], + o: null + }; + } + ns[ n[i] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( os[ o[i] ] == null ) { + os[ o[i] ] = { + rows: [], + n: null + }; + } + os[ o[i] ].rows.push( i ); + } + + for ( i in ns ) { + if ( !hasOwn.call( ns, i ) ) { + continue; + } + if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { + n[ ns[i].rows[0] ] = { + text: n[ ns[i].rows[0] ], + row: os[i].rows[0] + }; + o[ os[i].rows[0] ] = { + text: o[ os[i].rows[0] ], + row: ns[i].rows[0] + }; + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[ i + 1 ] == o[ n[i].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[i].row + 1 + }; + o[ n[i].row + 1 ] = { + text: o[ n[i].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[ i - 1 ] == o[ n[i].row - 1 ]) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[i].row - 1 + }; + o[ n[i].row - 1 ] = { + text: o[ n[i].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } + else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } + else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "<del>" + out.o[i] + oSpace[i] + "</del>"; + } + } + else { + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "<del>" + out.o[n] + oSpace[n] + "</del>"; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += "<ins>" + out.n[i] + nSpace[i] + "</ins>"; + } + else { + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "<del>" + out.o[n] + oSpace[n] + "</del>"; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +}()); + +// for CommonJS enviroments, export everything +if ( typeof exports !== "undefined" ) { + extend(exports, QUnit); +} + +// get at whatever the global object is, like window in browsers +}( (function() {return this;}.call()) )); diff --git a/web/src/vendor/benchmark/vendor/qunit/qunit/qunit.css b/web/src/vendor/benchmark/vendor/qunit/qunit/qunit.css new file mode 100644 index 00000000..257b224f --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit/qunit/qunit.css @@ -0,0 +1,231 @@ +/** + * QUnit v1.9.0 - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2012 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +/** Font Family and Sizes */ + +#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { + font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; +} + +#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } +#qunit-tests { font-size: smaller; } + + +/** Resets */ + +#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { + margin: 0; + padding: 0; +} + + +/** Header */ + +#qunit-header { + padding: 0.5em 0 0.5em 1em; + + color: #8699a4; + background-color: #0d3349; + + font-size: 1.5em; + line-height: 1em; + font-weight: normal; + + border-radius: 5px 5px 0 0; + -moz-border-radius: 5px 5px 0 0; + -webkit-border-top-right-radius: 5px; + -webkit-border-top-left-radius: 5px; +} + +#qunit-header a { + text-decoration: none; + color: #c2ccd1; +} + +#qunit-header a:hover, +#qunit-header a:focus { + color: #fff; +} + +#qunit-testrunner-toolbar label { + display: inline-block; + padding: 0 .5em 0 .1em; +} + +#qunit-banner { + height: 5px; +} + +#qunit-testrunner-toolbar { + padding: 0.5em 0 0.5em 2em; + color: #5E740B; + background-color: #eee; +} + +#qunit-userAgent { + padding: 0.5em 0 0.5em 2.5em; + background-color: #2b81af; + color: #fff; + text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; +} + + +/** Tests: Pass/Fail */ + +#qunit-tests { + list-style-position: inside; +} + +#qunit-tests li { + padding: 0.4em 0.5em 0.4em 2.5em; + border-bottom: 1px solid #fff; + list-style-position: inside; +} + +#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { + display: none; +} + +#qunit-tests li strong { + cursor: pointer; +} + +#qunit-tests li a { + padding: 0.5em; + color: #c2ccd1; + text-decoration: none; +} +#qunit-tests li a:hover, +#qunit-tests li a:focus { + color: #000; +} + +#qunit-tests ol { + margin-top: 0.5em; + padding: 0.5em; + + background-color: #fff; + + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +#qunit-tests table { + border-collapse: collapse; + margin-top: .2em; +} + +#qunit-tests th { + text-align: right; + vertical-align: top; + padding: 0 .5em 0 0; +} + +#qunit-tests td { + vertical-align: top; +} + +#qunit-tests pre { + margin: 0; + white-space: pre-wrap; + word-wrap: break-word; +} + +#qunit-tests del { + background-color: #e0f2be; + color: #374e0c; + text-decoration: none; +} + +#qunit-tests ins { + background-color: #ffcaca; + color: #500; + text-decoration: none; +} + +/*** Test Counts */ + +#qunit-tests b.counts { color: black; } +#qunit-tests b.passed { color: #5E740B; } +#qunit-tests b.failed { color: #710909; } + +#qunit-tests li li { + padding: 5px; + background-color: #fff; + border-bottom: none; + list-style-position: inside; +} + +/*** Passing Styles */ + +#qunit-tests li li.pass { + color: #3c510c; + background-color: #fff; + border-left: 10px solid #C6E746; +} + +#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } +#qunit-tests .pass .test-name { color: #366097; } + +#qunit-tests .pass .test-actual, +#qunit-tests .pass .test-expected { color: #999999; } + +#qunit-banner.qunit-pass { background-color: #C6E746; } + +/*** Failing Styles */ + +#qunit-tests li li.fail { + color: #710909; + background-color: #fff; + border-left: 10px solid #EE5757; + white-space: pre; +} + +#qunit-tests > li:last-child { + border-radius: 0 0 5px 5px; + -moz-border-radius: 0 0 5px 5px; + -webkit-border-bottom-right-radius: 5px; + -webkit-border-bottom-left-radius: 5px; +} + +#qunit-tests .fail { color: #000000; background-color: #EE5757; } +#qunit-tests .fail .test-name, +#qunit-tests .fail .module-name { color: #000000; } + +#qunit-tests .fail .test-actual { color: #EE5757; } +#qunit-tests .fail .test-expected { color: green; } + +#qunit-banner.qunit-fail { background-color: #EE5757; } + + +/** Result */ + +#qunit-testresult { + padding: 0.5em 0.5em 0.5em 2.5em; + + color: #2b81af; + background-color: #D2E0E6; + + border-bottom: 1px solid white; +} +#qunit-testresult .module-name { + font-weight: bold; +} + +/** Fixture */ + +#qunit-fixture { + position: absolute; + top: -10000px; + left: -10000px; + width: 1000px; + height: 1000px; +} diff --git a/web/src/vendor/benchmark/vendor/qunit/qunit/qunit.js b/web/src/vendor/benchmark/vendor/qunit/qunit/qunit.js new file mode 100644 index 00000000..9efedcb4 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/qunit/qunit/qunit.js @@ -0,0 +1,1932 @@ +/** + * QUnit v1.9.0 - A JavaScript Unit Testing Framework + * + * http://docs.jquery.com/QUnit + * + * Copyright (c) 2012 John Resig, Jörn Zaefferer + * Dual licensed under the MIT (MIT-LICENSE.txt) + * or GPL (GPL-LICENSE.txt) licenses. + */ + +(function( window ) { + +var QUnit, + config, + onErrorFnPrev, + testId = 0, + fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), + toString = Object.prototype.toString, + hasOwn = Object.prototype.hasOwnProperty, + defined = { + setTimeout: typeof window.setTimeout !== "undefined", + sessionStorage: (function() { + var x = "qunit-test-string"; + try { + sessionStorage.setItem( x, x ); + sessionStorage.removeItem( x ); + return true; + } catch( e ) { + return false; + } + }()) +}; + +function Test( settings ) { + extend( this, settings ); + this.assertions = []; + this.testNumber = ++Test.count; +} + +Test.count = 0; + +Test.prototype = { + init: function() { + var a, b, li, + tests = id( "qunit-tests" ); + + if ( tests ) { + b = document.createElement( "strong" ); + b.innerHTML = this.name; + + // `a` initialized at top of scope + a = document.createElement( "a" ); + a.innerHTML = "Rerun"; + a.href = QUnit.url({ testNumber: this.testNumber }); + + li = document.createElement( "li" ); + li.appendChild( b ); + li.appendChild( a ); + li.className = "running"; + li.id = this.id = "qunit-test-output" + testId++; + + tests.appendChild( li ); + } + }, + setup: function() { + if ( this.module !== config.previousModule ) { + if ( config.previousModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.previousModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + config.previousModule = this.module; + config.moduleStats = { all: 0, bad: 0 }; + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } else if ( config.autorun ) { + runLoggingCallbacks( "moduleStart", QUnit, { + name: this.module + }); + } + + config.current = this; + + this.testEnvironment = extend({ + setup: function() {}, + teardown: function() {} + }, this.moduleTestEnvironment ); + + runLoggingCallbacks( "testStart", QUnit, { + name: this.testName, + module: this.module + }); + + // allow utility functions to access the current test environment + // TODO why?? + QUnit.current_testEnvironment = this.testEnvironment; + + if ( !config.pollution ) { + saveGlobal(); + } + if ( config.notrycatch ) { + this.testEnvironment.setup.call( this.testEnvironment ); + return; + } + try { + this.testEnvironment.setup.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); + } + }, + run: function() { + config.current = this; + + var running = id( "qunit-testresult" ); + + if ( running ) { + running.innerHTML = "Running: <br/>" + this.name; + } + + if ( this.async ) { + QUnit.stop(); + } + + if ( config.notrycatch ) { + this.callback.call( this.testEnvironment, QUnit.assert ); + return; + } + + try { + this.callback.call( this.testEnvironment, QUnit.assert ); + } catch( e ) { + QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) ); + // else next test will carry the responsibility + saveGlobal(); + + // Restart the tests if they're blocking + if ( config.blocking ) { + QUnit.start(); + } + } + }, + teardown: function() { + config.current = this; + if ( config.notrycatch ) { + this.testEnvironment.teardown.call( this.testEnvironment ); + return; + } else { + try { + this.testEnvironment.teardown.call( this.testEnvironment ); + } catch( e ) { + QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); + } + } + checkPollution(); + }, + finish: function() { + config.current = this; + if ( config.requireExpects && this.expected == null ) { + QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); + } else if ( this.expected != null && this.expected != this.assertions.length ) { + QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); + } else if ( this.expected == null && !this.assertions.length ) { + QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); + } + + var assertion, a, b, i, li, ol, + test = this, + good = 0, + bad = 0, + tests = id( "qunit-tests" ); + + config.stats.all += this.assertions.length; + config.moduleStats.all += this.assertions.length; + + if ( tests ) { + ol = document.createElement( "ol" ); + + for ( i = 0; i < this.assertions.length; i++ ) { + assertion = this.assertions[i]; + + li = document.createElement( "li" ); + li.className = assertion.result ? "pass" : "fail"; + li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); + ol.appendChild( li ); + + if ( assertion.result ) { + good++; + } else { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + + // store result when possible + if ( QUnit.config.reorder && defined.sessionStorage ) { + if ( bad ) { + sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); + } else { + sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); + } + } + + if ( bad === 0 ) { + ol.style.display = "none"; + } + + // `b` initialized at top of scope + b = document.createElement( "strong" ); + b.innerHTML = this.name + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>"; + + addEvent(b, "click", function() { + var next = b.nextSibling.nextSibling, + display = next.style.display; + next.style.display = display === "none" ? "block" : "none"; + }); + + addEvent(b, "dblclick", function( e ) { + var target = e && e.target ? e.target : window.event.srcElement; + if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { + target = target.parentNode; + } + if ( window.location && target.nodeName.toLowerCase() === "strong" ) { + window.location = QUnit.url({ testNumber: test.testNumber }); + } + }); + + // `li` initialized at top of scope + li = id( this.id ); + li.className = bad ? "fail" : "pass"; + li.removeChild( li.firstChild ); + a = li.firstChild; + li.appendChild( b ); + li.appendChild ( a ); + li.appendChild( ol ); + + } else { + for ( i = 0; i < this.assertions.length; i++ ) { + if ( !this.assertions[i].result ) { + bad++; + config.stats.bad++; + config.moduleStats.bad++; + } + } + } + + runLoggingCallbacks( "testDone", QUnit, { + name: this.testName, + module: this.module, + failed: bad, + passed: this.assertions.length - bad, + total: this.assertions.length + }); + + QUnit.reset(); + + config.current = undefined; + }, + + queue: function() { + var bad, + test = this; + + synchronize(function() { + test.init(); + }); + function run() { + // each of these can by async + synchronize(function() { + test.setup(); + }); + synchronize(function() { + test.run(); + }); + synchronize(function() { + test.teardown(); + }); + synchronize(function() { + test.finish(); + }); + } + + // `bad` initialized at top of scope + // defer when previous test run passed, if storage is available + bad = QUnit.config.reorder && defined.sessionStorage && + +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); + + if ( bad ) { + run(); + } else { + synchronize( run, true ); + } + } +}; + +// Root QUnit object. +// `QUnit` initialized at top of scope +QUnit = { + + // call on start of module test to prepend name to all tests + module: function( name, testEnvironment ) { + config.currentModule = name; + config.currentModuleTestEnviroment = testEnvironment; + }, + + asyncTest: function( testName, expected, callback ) { + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + QUnit.test( testName, expected, callback, true ); + }, + + test: function( testName, expected, callback, async ) { + var test, + name = "<span class='test-name'>" + escapeInnerText( testName ) + "</span>"; + + if ( arguments.length === 2 ) { + callback = expected; + expected = null; + } + + if ( config.currentModule ) { + name = "<span class='module-name'>" + config.currentModule + "</span>: " + name; + } + + test = new Test({ + name: name, + testName: testName, + expected: expected, + async: async, + callback: callback, + module: config.currentModule, + moduleTestEnvironment: config.currentModuleTestEnviroment, + stack: sourceFromStacktrace( 2 ) + }); + + if ( !validTest( test ) ) { + return; + } + + test.queue(); + }, + + // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. + expect: function( asserts ) { + config.current.expected = asserts; + }, + + start: function( count ) { + config.semaphore -= count || 1; + // don't start until equal number of stop-calls + if ( config.semaphore > 0 ) { + return; + } + // ignore if start is called more often then stop + if ( config.semaphore < 0 ) { + config.semaphore = 0; + } + // A slight delay, to avoid any current callbacks + if ( defined.setTimeout ) { + window.setTimeout(function() { + if ( config.semaphore > 0 ) { + return; + } + if ( config.timeout ) { + clearTimeout( config.timeout ); + } + + config.blocking = false; + process( true ); + }, 13); + } else { + config.blocking = false; + process( true ); + } + }, + + stop: function( count ) { + config.semaphore += count || 1; + config.blocking = true; + + if ( config.testTimeout && defined.setTimeout ) { + clearTimeout( config.timeout ); + config.timeout = window.setTimeout(function() { + QUnit.ok( false, "Test timed out" ); + config.semaphore = 1; + QUnit.start(); + }, config.testTimeout ); + } + } +}; + +// Asssert helpers +// All of these must call either QUnit.push() or manually do: +// - runLoggingCallbacks( "log", .. ); +// - config.current.assertions.push({ .. }); +QUnit.assert = { + /** + * Asserts rough true-ish result. + * @name ok + * @function + * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); + */ + ok: function( result, msg ) { + if ( !config.current ) { + throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + result = !!result; + + var source, + details = { + result: result, + message: msg + }; + + msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); + msg = "<span class='test-message'>" + msg + "</span>"; + + if ( !result ) { + source = sourceFromStacktrace( 2 ); + if ( source ) { + details.source = source; + msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr></table>"; + } + } + runLoggingCallbacks( "log", QUnit, details ); + config.current.assertions.push({ + result: result, + message: msg + }); + }, + + /** + * Assert that the first two arguments are equal, with an optional message. + * Prints out both actual and expected values. + * @name equal + * @function + * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); + */ + equal: function( actual, expected, message ) { + QUnit.push( expected == actual, actual, expected, message ); + }, + + /** + * @name notEqual + * @function + */ + notEqual: function( actual, expected, message ) { + QUnit.push( expected != actual, actual, expected, message ); + }, + + /** + * @name deepEqual + * @function + */ + deepEqual: function( actual, expected, message ) { + QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name notDeepEqual + * @function + */ + notDeepEqual: function( actual, expected, message ) { + QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); + }, + + /** + * @name strictEqual + * @function + */ + strictEqual: function( actual, expected, message ) { + QUnit.push( expected === actual, actual, expected, message ); + }, + + /** + * @name notStrictEqual + * @function + */ + notStrictEqual: function( actual, expected, message ) { + QUnit.push( expected !== actual, actual, expected, message ); + }, + + throws: function( block, expected, message ) { + var actual, + ok = false; + + // 'expected' is optional + if ( typeof expected === "string" ) { + message = expected; + expected = null; + } + + config.current.ignoreGlobalErrors = true; + try { + block.call( config.current.testEnvironment ); + } catch (e) { + actual = e; + } + config.current.ignoreGlobalErrors = false; + + if ( actual ) { + // we don't want to validate thrown error + if ( !expected ) { + ok = true; + // expected is a regexp + } else if ( QUnit.objectType( expected ) === "regexp" ) { + ok = expected.test( actual ); + // expected is a constructor + } else if ( actual instanceof expected ) { + ok = true; + // expected is a validation function which returns true is validation passed + } else if ( expected.call( {}, actual ) === true ) { + ok = true; + } + + QUnit.push( ok, actual, null, message ); + } else { + QUnit.pushFailure( message, null, 'No exception was thrown.' ); + } + } +}; + +/** + * @deprecate since 1.8.0 + * Kept assertion helpers in root for backwards compatibility + */ +extend( QUnit, QUnit.assert ); + +/** + * @deprecated since 1.9.0 + * Kept global "raises()" for backwards compatibility + */ +QUnit.raises = QUnit.assert.throws; + +/** + * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 + * Kept to avoid TypeErrors for undefined methods. + */ +QUnit.equals = function() { + QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); +}; +QUnit.same = function() { + QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); +}; + +// We want access to the constructor's prototype +(function() { + function F() {} + F.prototype = QUnit; + QUnit = new F(); + // Make F QUnit's constructor so that we can add to the prototype later + QUnit.constructor = F; +}()); + +/** + * Config object: Maintain internal state + * Later exposed as QUnit.config + * `config` initialized at top of scope + */ +config = { + // The queue of tests to run + queue: [], + + // block until document ready + blocking: true, + + // when enabled, show only failing tests + // gets persisted through sessionStorage and can be changed in UI via checkbox + hidepassed: false, + + // by default, run previously failed tests first + // very useful in combination with "Hide passed tests" checked + reorder: true, + + // by default, modify document.title when suite is done + altertitle: true, + + // when enabled, all tests must call expect() + requireExpects: false, + + // add checkboxes that are persisted in the query-string + // when enabled, the id is set to `true` as a `QUnit.config` property + urlConfig: [ + { + id: "noglobals", + label: "Check for Globals", + tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." + }, + { + id: "notrycatch", + label: "No try-catch", + tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." + } + ], + + // logging callback queues + begin: [], + done: [], + log: [], + testStart: [], + testDone: [], + moduleStart: [], + moduleDone: [] +}; + +// Initialize more QUnit.config and QUnit.urlParams +(function() { + var i, + location = window.location || { search: "", protocol: "file:" }, + params = location.search.slice( 1 ).split( "&" ), + length = params.length, + urlParams = {}, + current; + + if ( params[ 0 ] ) { + for ( i = 0; i < length; i++ ) { + current = params[ i ].split( "=" ); + current[ 0 ] = decodeURIComponent( current[ 0 ] ); + // allow just a key to turn on a flag, e.g., test.html?noglobals + current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; + urlParams[ current[ 0 ] ] = current[ 1 ]; + } + } + + QUnit.urlParams = urlParams; + + // String search anywhere in moduleName+testName + config.filter = urlParams.filter; + + // Exact match of the module name + config.module = urlParams.module; + + config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; + + // Figure out if we're running the tests from a server or not + QUnit.isLocal = location.protocol === "file:"; +}()); + +// Export global variables, unless an 'exports' object exists, +// in that case we assume we're in CommonJS (dealt with on the bottom of the script) +if ( typeof exports === "undefined" ) { + extend( window, QUnit ); + + // Expose QUnit object + window.QUnit = QUnit; +} + +// Extend QUnit object, +// these after set here because they should not be exposed as global functions +extend( QUnit, { + config: config, + + // Initialize the configuration options + init: function() { + extend( config, { + stats: { all: 0, bad: 0 }, + moduleStats: { all: 0, bad: 0 }, + started: +new Date(), + updateRate: 1000, + blocking: false, + autostart: true, + autorun: false, + filter: "", + queue: [], + semaphore: 0 + }); + + var tests, banner, result, + qunit = id( "qunit" ); + + if ( qunit ) { + qunit.innerHTML = + "<h1 id='qunit-header'>" + escapeInnerText( document.title ) + "</h1>" + + "<h2 id='qunit-banner'></h2>" + + "<div id='qunit-testrunner-toolbar'></div>" + + "<h2 id='qunit-userAgent'></h2>" + + "<ol id='qunit-tests'></ol>"; + } + + tests = id( "qunit-tests" ); + banner = id( "qunit-banner" ); + result = id( "qunit-testresult" ); + + if ( tests ) { + tests.innerHTML = ""; + } + + if ( banner ) { + banner.className = ""; + } + + if ( result ) { + result.parentNode.removeChild( result ); + } + + if ( tests ) { + result = document.createElement( "p" ); + result.id = "qunit-testresult"; + result.className = "result"; + tests.parentNode.insertBefore( result, tests ); + result.innerHTML = "Running...<br/> "; + } + }, + + // Resets the test setup. Useful for tests that modify the DOM. + // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. + reset: function() { + var fixture; + + if ( window.jQuery ) { + jQuery( "#qunit-fixture" ).html( config.fixture ); + } else { + fixture = id( "qunit-fixture" ); + if ( fixture ) { + fixture.innerHTML = config.fixture; + } + } + }, + + // Trigger an event on an element. + // @example triggerEvent( document.body, "click" ); + triggerEvent: function( elem, type, event ) { + if ( document.createEvent ) { + event = document.createEvent( "MouseEvents" ); + event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, + 0, 0, 0, 0, 0, false, false, false, false, 0, null); + + elem.dispatchEvent( event ); + } else if ( elem.fireEvent ) { + elem.fireEvent( "on" + type ); + } + }, + + // Safe object type checking + is: function( type, obj ) { + return QUnit.objectType( obj ) == type; + }, + + objectType: function( obj ) { + if ( typeof obj === "undefined" ) { + return "undefined"; + // consider: typeof null === object + } + if ( obj === null ) { + return "null"; + } + + var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; + + switch ( type ) { + case "Number": + if ( isNaN(obj) ) { + return "nan"; + } + return "number"; + case "String": + case "Boolean": + case "Array": + case "Date": + case "RegExp": + case "Function": + return type.toLowerCase(); + } + if ( typeof obj === "object" ) { + return "object"; + } + return undefined; + }, + + push: function( result, actual, expected, message ) { + if ( !config.current ) { + throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); + } + + var output, source, + details = { + result: result, + message: message, + actual: actual, + expected: expected + }; + + message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); + message = "<span class='test-message'>" + message + "</span>"; + output = message; + + if ( !result ) { + expected = escapeInnerText( QUnit.jsDump.parse(expected) ); + actual = escapeInnerText( QUnit.jsDump.parse(actual) ); + output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>"; + + if ( actual != expected ) { + output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>"; + output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>"; + } + + source = sourceFromStacktrace(); + + if ( source ) { + details.source = source; + output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; + } + + output += "</table>"; + } + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: !!result, + message: output + }); + }, + + pushFailure: function( message, source, actual ) { + if ( !config.current ) { + throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); + } + + var output, + details = { + result: false, + message: message + }; + + message = escapeInnerText( message ) || "error"; + message = "<span class='test-message'>" + message + "</span>"; + output = message; + + output += "<table>"; + + if ( actual ) { + output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeInnerText( actual ) + "</pre></td></tr>"; + } + + if ( source ) { + details.source = source; + output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeInnerText( source ) + "</pre></td></tr>"; + } + + output += "</table>"; + + runLoggingCallbacks( "log", QUnit, details ); + + config.current.assertions.push({ + result: false, + message: output + }); + }, + + url: function( params ) { + params = extend( extend( {}, QUnit.urlParams ), params ); + var key, + querystring = "?"; + + for ( key in params ) { + if ( !hasOwn.call( params, key ) ) { + continue; + } + querystring += encodeURIComponent( key ) + "=" + + encodeURIComponent( params[ key ] ) + "&"; + } + return window.location.pathname + querystring.slice( 0, -1 ); + }, + + extend: extend, + id: id, + addEvent: addEvent + // load, equiv, jsDump, diff: Attached later +}); + +/** + * @deprecated: Created for backwards compatibility with test runner that set the hook function + * into QUnit.{hook}, instead of invoking it and passing the hook function. + * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. + * Doing this allows us to tell if the following methods have been overwritten on the actual + * QUnit object. + */ +extend( QUnit.constructor.prototype, { + + // Logging callbacks; all receive a single argument with the listed properties + // run test/logs.html for any related changes + begin: registerLoggingCallback( "begin" ), + + // done: { failed, passed, total, runtime } + done: registerLoggingCallback( "done" ), + + // log: { result, actual, expected, message } + log: registerLoggingCallback( "log" ), + + // testStart: { name } + testStart: registerLoggingCallback( "testStart" ), + + // testDone: { name, failed, passed, total } + testDone: registerLoggingCallback( "testDone" ), + + // moduleStart: { name } + moduleStart: registerLoggingCallback( "moduleStart" ), + + // moduleDone: { name, failed, passed, total } + moduleDone: registerLoggingCallback( "moduleDone" ) +}); + +if ( typeof document === "undefined" || document.readyState === "complete" ) { + config.autorun = true; +} + +QUnit.load = function() { + runLoggingCallbacks( "begin", QUnit, {} ); + + // Initialize the config, saving the execution queue + var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, + urlConfigHtml = "", + oldconfig = extend( {}, config ); + + QUnit.init(); + extend(config, oldconfig); + + config.blocking = false; + + len = config.urlConfig.length; + + for ( i = 0; i < len; i++ ) { + val = config.urlConfig[i]; + if ( typeof val === "string" ) { + val = { + id: val, + label: val, + tooltip: "[no tooltip available]" + }; + } + config[ val.id ] = QUnit.urlParams[ val.id ]; + urlConfigHtml += "<input id='qunit-urlconfig-" + val.id + "' name='" + val.id + "' type='checkbox'" + ( config[ val.id ] ? " checked='checked'" : "" ) + " title='" + val.tooltip + "'><label for='qunit-urlconfig-" + val.id + "' title='" + val.tooltip + "'>" + val.label + "</label>"; + } + + // `userAgent` initialized at top of scope + userAgent = id( "qunit-userAgent" ); + if ( userAgent ) { + userAgent.innerHTML = navigator.userAgent; + } + + // `banner` initialized at top of scope + banner = id( "qunit-header" ); + if ( banner ) { + banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> "; + } + + // `toolbar` initialized at top of scope + toolbar = id( "qunit-testrunner-toolbar" ); + if ( toolbar ) { + // `filter` initialized at top of scope + filter = document.createElement( "input" ); + filter.type = "checkbox"; + filter.id = "qunit-filter-pass"; + + addEvent( filter, "click", function() { + var tmp, + ol = document.getElementById( "qunit-tests" ); + + if ( filter.checked ) { + ol.className = ol.className + " hidepass"; + } else { + tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; + ol.className = tmp.replace( / hidepass /, " " ); + } + if ( defined.sessionStorage ) { + if (filter.checked) { + sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); + } else { + sessionStorage.removeItem( "qunit-filter-passed-tests" ); + } + } + }); + + if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { + filter.checked = true; + // `ol` initialized at top of scope + ol = document.getElementById( "qunit-tests" ); + ol.className = ol.className + " hidepass"; + } + toolbar.appendChild( filter ); + + // `label` initialized at top of scope + label = document.createElement( "label" ); + label.setAttribute( "for", "qunit-filter-pass" ); + label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); + label.innerHTML = "Hide passed tests"; + toolbar.appendChild( label ); + + urlConfigCheckboxes = document.createElement( 'span' ); + urlConfigCheckboxes.innerHTML = urlConfigHtml; + addEvent( urlConfigCheckboxes, "change", function( event ) { + var params = {}; + params[ event.target.name ] = event.target.checked ? true : undefined; + window.location = QUnit.url( params ); + }); + toolbar.appendChild( urlConfigCheckboxes ); + } + + // `main` initialized at top of scope + main = id( "qunit-fixture" ); + if ( main ) { + config.fixture = main.innerHTML; + } + + if ( config.autostart ) { + QUnit.start(); + } +}; + +addEvent( window, "load", QUnit.load ); + +// `onErrorFnPrev` initialized at top of scope +// Preserve other handlers +onErrorFnPrev = window.onerror; + +// Cover uncaught exceptions +// Returning true will surpress the default browser handler, +// returning false will let it run. +window.onerror = function ( error, filePath, linerNr ) { + var ret = false; + if ( onErrorFnPrev ) { + ret = onErrorFnPrev( error, filePath, linerNr ); + } + + // Treat return value as window.onerror itself does, + // Only do our handling if not surpressed. + if ( ret !== true ) { + if ( QUnit.config.current ) { + if ( QUnit.config.current.ignoreGlobalErrors ) { + return true; + } + QUnit.pushFailure( error, filePath + ":" + linerNr ); + } else { + QUnit.test( "global failure", function() { + QUnit.pushFailure( error, filePath + ":" + linerNr ); + }); + } + return false; + } + + return ret; +}; + +function done() { + config.autorun = true; + + // Log the last module results + if ( config.currentModule ) { + runLoggingCallbacks( "moduleDone", QUnit, { + name: config.currentModule, + failed: config.moduleStats.bad, + passed: config.moduleStats.all - config.moduleStats.bad, + total: config.moduleStats.all + }); + } + + var i, key, + banner = id( "qunit-banner" ), + tests = id( "qunit-tests" ), + runtime = +new Date() - config.started, + passed = config.stats.all - config.stats.bad, + html = [ + "Tests completed in ", + runtime, + " milliseconds.<br/>", + "<span class='passed'>", + passed, + "</span> tests of <span class='total'>", + config.stats.all, + "</span> passed, <span class='failed'>", + config.stats.bad, + "</span> failed." + ].join( "" ); + + if ( banner ) { + banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); + } + + if ( tests ) { + id( "qunit-testresult" ).innerHTML = html; + } + + if ( config.altertitle && typeof document !== "undefined" && document.title ) { + // show ✖ for good, ✔ for bad suite result in title + // use escape sequences in case file gets loaded with non-utf-8-charset + document.title = [ + ( config.stats.bad ? "\u2716" : "\u2714" ), + document.title.replace( /^[\u2714\u2716] /i, "" ) + ].join( " " ); + } + + // clear own sessionStorage items if all tests passed + if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { + // `key` & `i` initialized at top of scope + for ( i = 0; i < sessionStorage.length; i++ ) { + key = sessionStorage.key( i++ ); + if ( key.indexOf( "qunit-test-" ) === 0 ) { + sessionStorage.removeItem( key ); + } + } + } + + runLoggingCallbacks( "done", QUnit, { + failed: config.stats.bad, + passed: passed, + total: config.stats.all, + runtime: runtime + }); +} + +/** @return Boolean: true if this test should be ran */ +function validTest( test ) { + var include, + filter = config.filter && config.filter.toLowerCase(), + module = config.module && config.module.toLowerCase(), + fullName = (test.module + ": " + test.testName).toLowerCase(); + + if ( config.testNumber ) { + return test.testNumber === config.testNumber; + } + + if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { + return false; + } + + if ( !filter ) { + return true; + } + + include = filter.charAt( 0 ) !== "!"; + if ( !include ) { + filter = filter.slice( 1 ); + } + + // If the filter matches, we need to honour include + if ( fullName.indexOf( filter ) !== -1 ) { + return include; + } + + // Otherwise, do the opposite + return !include; +} + +// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) +// Later Safari and IE10 are supposed to support error.stack as well +// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack +function extractStacktrace( e, offset ) { + offset = offset === undefined ? 3 : offset; + + var stack, include, i, regex; + + if ( e.stacktrace ) { + // Opera + return e.stacktrace.split( "\n" )[ offset + 3 ]; + } else if ( e.stack ) { + // Firefox, Chrome + stack = e.stack.split( "\n" ); + if (/^error$/i.test( stack[0] ) ) { + stack.shift(); + } + if ( fileName ) { + include = []; + for ( i = offset; i < stack.length; i++ ) { + if ( stack[ i ].indexOf( fileName ) != -1 ) { + break; + } + include.push( stack[ i ] ); + } + if ( include.length ) { + return include.join( "\n" ); + } + } + return stack[ offset ]; + } else if ( e.sourceURL ) { + // Safari, PhantomJS + // hopefully one day Safari provides actual stacktraces + // exclude useless self-reference for generated Error objects + if ( /qunit.js$/.test( e.sourceURL ) ) { + return; + } + // for actual exceptions, this is useful + return e.sourceURL + ":" + e.line; + } +} +function sourceFromStacktrace( offset ) { + try { + throw new Error(); + } catch ( e ) { + return extractStacktrace( e, offset ); + } +} + +function escapeInnerText( s ) { + if ( !s ) { + return ""; + } + s = s + ""; + return s.replace( /[\&<>]/g, function( s ) { + switch( s ) { + case "&": return "&"; + case "<": return "<"; + case ">": return ">"; + default: return s; + } + }); +} + +function synchronize( callback, last ) { + config.queue.push( callback ); + + if ( config.autorun && !config.blocking ) { + process( last ); + } +} + +function process( last ) { + function next() { + process( last ); + } + var start = new Date().getTime(); + config.depth = config.depth ? config.depth + 1 : 1; + + while ( config.queue.length && !config.blocking ) { + if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { + config.queue.shift()(); + } else { + window.setTimeout( next, 13 ); + break; + } + } + config.depth--; + if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { + done(); + } +} + +function saveGlobal() { + config.pollution = []; + + if ( config.noglobals ) { + for ( var key in window ) { + // in Opera sometimes DOM element ids show up here, ignore them + if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { + continue; + } + config.pollution.push( key ); + } + } +} + +function checkPollution( name ) { + var newGlobals, + deletedGlobals, + old = config.pollution; + + saveGlobal(); + + newGlobals = diff( config.pollution, old ); + if ( newGlobals.length > 0 ) { + QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); + } + + deletedGlobals = diff( old, config.pollution ); + if ( deletedGlobals.length > 0 ) { + QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); + } +} + +// returns a new Array with the elements that are in a but not in b +function diff( a, b ) { + var i, j, + result = a.slice(); + + for ( i = 0; i < result.length; i++ ) { + for ( j = 0; j < b.length; j++ ) { + if ( result[i] === b[j] ) { + result.splice( i, 1 ); + i--; + break; + } + } + } + return result; +} + +function extend( a, b ) { + for ( var prop in b ) { + if ( b[ prop ] === undefined ) { + delete a[ prop ]; + + // Avoid "Member not found" error in IE8 caused by setting window.constructor + } else if ( prop !== "constructor" || a !== window ) { + a[ prop ] = b[ prop ]; + } + } + + return a; +} + +function addEvent( elem, type, fn ) { + if ( elem.addEventListener ) { + elem.addEventListener( type, fn, false ); + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, fn ); + } else { + fn(); + } +} + +function id( name ) { + return !!( typeof document !== "undefined" && document && document.getElementById ) && + document.getElementById( name ); +} + +function registerLoggingCallback( key ) { + return function( callback ) { + config[key].push( callback ); + }; +} + +// Supports deprecated method of completely overwriting logging callbacks +function runLoggingCallbacks( key, scope, args ) { + //debugger; + var i, callbacks; + if ( QUnit.hasOwnProperty( key ) ) { + QUnit[ key ].call(scope, args ); + } else { + callbacks = config[ key ]; + for ( i = 0; i < callbacks.length; i++ ) { + callbacks[ i ].call( scope, args ); + } + } +} + +// Test for equality any JavaScript type. +// Author: Philippe Rathé <prathe@gmail.com> +QUnit.equiv = (function() { + + // Call the o related callback with the given arguments. + function bindCallbacks( o, callbacks, args ) { + var prop = QUnit.objectType( o ); + if ( prop ) { + if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { + return callbacks[ prop ].apply( callbacks, args ); + } else { + return callbacks[ prop ]; // or undefined + } + } + } + + // the real equiv function + var innerEquiv, + // stack to decide between skip/abort functions + callers = [], + // stack to avoiding loops from circular referencing + parents = [], + + getProto = Object.getPrototypeOf || function ( obj ) { + return obj.__proto__; + }, + callbacks = (function () { + + // for string, boolean, number and null + function useStrictEquality( b, a ) { + if ( b instanceof a.constructor || a instanceof b.constructor ) { + // to catch short annotaion VS 'new' annotation of a + // declaration + // e.g. var i = 1; + // var j = new Number(1); + return a == b; + } else { + return a === b; + } + } + + return { + "string": useStrictEquality, + "boolean": useStrictEquality, + "number": useStrictEquality, + "null": useStrictEquality, + "undefined": useStrictEquality, + + "nan": function( b ) { + return isNaN( b ); + }, + + "date": function( b, a ) { + return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); + }, + + "regexp": function( b, a ) { + return QUnit.objectType( b ) === "regexp" && + // the regex itself + a.source === b.source && + // and its modifers + a.global === b.global && + // (gmi) ... + a.ignoreCase === b.ignoreCase && + a.multiline === b.multiline; + }, + + // - skip when the property is a method of an instance (OOP) + // - abort otherwise, + // initial === would have catch identical references anyway + "function": function() { + var caller = callers[callers.length - 1]; + return caller !== Object && typeof caller !== "undefined"; + }, + + "array": function( b, a ) { + var i, j, len, loop; + + // b could be an object literal here + if ( QUnit.objectType( b ) !== "array" ) { + return false; + } + + len = a.length; + if ( len !== b.length ) { + // safe and faster + return false; + } + + // track reference to avoid circular references + parents.push( a ); + for ( i = 0; i < len; i++ ) { + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + loop = true;// dont rewalk array + } + } + if ( !loop && !innerEquiv(a[i], b[i]) ) { + parents.pop(); + return false; + } + } + parents.pop(); + return true; + }, + + "object": function( b, a ) { + var i, j, loop, + // Default to true + eq = true, + aProperties = [], + bProperties = []; + + // comparing constructors is more strict than using + // instanceof + if ( a.constructor !== b.constructor ) { + // Allow objects with no prototype to be equivalent to + // objects with Object as their constructor. + if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || + ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { + return false; + } + } + + // stack constructor before traversing properties + callers.push( a.constructor ); + // track reference to avoid circular references + parents.push( a ); + + for ( i in a ) { // be strict: don't ensures hasOwnProperty + // and go deep + loop = false; + for ( j = 0; j < parents.length; j++ ) { + if ( parents[j] === a[i] ) { + // don't go down the same path twice + loop = true; + } + } + aProperties.push(i); // collect a's properties + + if (!loop && !innerEquiv( a[i], b[i] ) ) { + eq = false; + break; + } + } + + callers.pop(); // unstack, we are done + parents.pop(); + + for ( i in b ) { + bProperties.push( i ); // collect b's properties + } + + // Ensures identical properties name + return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); + } + }; + }()); + + innerEquiv = function() { // can take multiple arguments + var args = [].slice.apply( arguments ); + if ( args.length < 2 ) { + return true; // end transition + } + + return (function( a, b ) { + if ( a === b ) { + return true; // catch the most you can + } else if ( a === null || b === null || typeof a === "undefined" || + typeof b === "undefined" || + QUnit.objectType(a) !== QUnit.objectType(b) ) { + return false; // don't lose time with error prone cases + } else { + return bindCallbacks(a, callbacks, [ b, a ]); + } + + // apply transition with (1..n) arguments + }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); + }; + + return innerEquiv; +}()); + +/** + * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | + * http://flesler.blogspot.com Licensed under BSD + * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 + * + * @projectDescription Advanced and extensible data dumping for Javascript. + * @version 1.0.0 + * @author Ariel Flesler + * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} + */ +QUnit.jsDump = (function() { + function quote( str ) { + return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; + } + function literal( o ) { + return o + ""; + } + function join( pre, arr, post ) { + var s = jsDump.separator(), + base = jsDump.indent(), + inner = jsDump.indent(1); + if ( arr.join ) { + arr = arr.join( "," + s + inner ); + } + if ( !arr ) { + return pre + post; + } + return [ pre, inner + arr, base + post ].join(s); + } + function array( arr, stack ) { + var i = arr.length, ret = new Array(i); + this.up(); + while ( i-- ) { + ret[i] = this.parse( arr[i] , undefined , stack); + } + this.down(); + return join( "[", ret, "]" ); + } + + var reName = /^function (\w+)/, + jsDump = { + parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance + stack = stack || [ ]; + var inStack, res, + parser = this.parsers[ type || this.typeOf(obj) ]; + + type = typeof parser; + inStack = inArray( obj, stack ); + + if ( inStack != -1 ) { + return "recursion(" + (inStack - stack.length) + ")"; + } + //else + if ( type == "function" ) { + stack.push( obj ); + res = parser.call( this, obj, stack ); + stack.pop(); + return res; + } + // else + return ( type == "string" ) ? parser : this.parsers.error; + }, + typeOf: function( obj ) { + var type; + if ( obj === null ) { + type = "null"; + } else if ( typeof obj === "undefined" ) { + type = "undefined"; + } else if ( QUnit.is( "regexp", obj) ) { + type = "regexp"; + } else if ( QUnit.is( "date", obj) ) { + type = "date"; + } else if ( QUnit.is( "function", obj) ) { + type = "function"; + } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { + type = "window"; + } else if ( obj.nodeType === 9 ) { + type = "document"; + } else if ( obj.nodeType ) { + type = "node"; + } else if ( + // native arrays + toString.call( obj ) === "[object Array]" || + // NodeList objects + ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) + ) { + type = "array"; + } else { + type = typeof obj; + } + return type; + }, + separator: function() { + return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? " " : " "; + }, + indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing + if ( !this.multiline ) { + return ""; + } + var chr = this.indentChar; + if ( this.HTML ) { + chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); + } + return new Array( this._depth_ + (extra||0) ).join(chr); + }, + up: function( a ) { + this._depth_ += a || 1; + }, + down: function( a ) { + this._depth_ -= a || 1; + }, + setParser: function( name, parser ) { + this.parsers[name] = parser; + }, + // The next 3 are exposed so you can use them + quote: quote, + literal: literal, + join: join, + // + _depth_: 1, + // This is the list of parsers, to modify them, use jsDump.setParser + parsers: { + window: "[Window]", + document: "[Document]", + error: "[ERROR]", //when no parser is found, shouldn"t happen + unknown: "[Unknown]", + "null": "null", + "undefined": "undefined", + "function": function( fn ) { + var ret = "function", + name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE + + if ( name ) { + ret += " " + name; + } + ret += "( "; + + ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); + return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); + }, + array: array, + nodelist: array, + "arguments": array, + object: function( map, stack ) { + var ret = [ ], keys, key, val, i; + QUnit.jsDump.up(); + if ( Object.keys ) { + keys = Object.keys( map ); + } else { + keys = []; + for ( key in map ) { + keys.push( key ); + } + } + keys.sort(); + for ( i = 0; i < keys.length; i++ ) { + key = keys[ i ]; + val = map[ key ]; + ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); + } + QUnit.jsDump.down(); + return join( "{", ret, "}" ); + }, + node: function( node ) { + var a, val, + open = QUnit.jsDump.HTML ? "<" : "<", + close = QUnit.jsDump.HTML ? ">" : ">", + tag = node.nodeName.toLowerCase(), + ret = open + tag; + + for ( a in QUnit.jsDump.DOMAttrs ) { + val = node[ QUnit.jsDump.DOMAttrs[a] ]; + if ( val ) { + ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); + } + } + return ret + close + open + "/" + tag + close; + }, + functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function + var args, + l = fn.length; + + if ( !l ) { + return ""; + } + + args = new Array(l); + while ( l-- ) { + args[l] = String.fromCharCode(97+l);//97 is 'a' + } + return " " + args.join( ", " ) + " "; + }, + key: quote, //object calls it internally, the key part of an item in a map + functionCode: "[code]", //function calls it internally, it's the content of the function + attribute: quote, //node calls it internally, it's an html attribute value + string: quote, + date: quote, + regexp: literal, //regex + number: literal, + "boolean": literal + }, + DOMAttrs: { + //attributes to dump from nodes, name=>realName + id: "id", + name: "name", + "class": "className" + }, + HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) + indentChar: " ",//indentation unit + multiline: true //if true, items in a collection, are separated by a \n, else just a space. + }; + + return jsDump; +}()); + +// from Sizzle.js +function getText( elems ) { + var i, elem, + ret = ""; + + for ( i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +} + +// from jquery.js +function inArray( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; +} + +/* + * Javascript Diff Algorithm + * By John Resig (http://ejohn.org/) + * Modified by Chu Alan "sprite" + * + * Released under the MIT license. + * + * More Info: + * http://ejohn.org/projects/javascript-diff-algorithm/ + * + * Usage: QUnit.diff(expected, actual) + * + * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over" + */ +QUnit.diff = (function() { + function diff( o, n ) { + var i, + ns = {}, + os = {}; + + for ( i = 0; i < n.length; i++ ) { + if ( ns[ n[i] ] == null ) { + ns[ n[i] ] = { + rows: [], + o: null + }; + } + ns[ n[i] ].rows.push( i ); + } + + for ( i = 0; i < o.length; i++ ) { + if ( os[ o[i] ] == null ) { + os[ o[i] ] = { + rows: [], + n: null + }; + } + os[ o[i] ].rows.push( i ); + } + + for ( i in ns ) { + if ( !hasOwn.call( ns, i ) ) { + continue; + } + if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { + n[ ns[i].rows[0] ] = { + text: n[ ns[i].rows[0] ], + row: os[i].rows[0] + }; + o[ os[i].rows[0] ] = { + text: o[ os[i].rows[0] ], + row: ns[i].rows[0] + }; + } + } + + for ( i = 0; i < n.length - 1; i++ ) { + if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && + n[ i + 1 ] == o[ n[i].row + 1 ] ) { + + n[ i + 1 ] = { + text: n[ i + 1 ], + row: n[i].row + 1 + }; + o[ n[i].row + 1 ] = { + text: o[ n[i].row + 1 ], + row: i + 1 + }; + } + } + + for ( i = n.length - 1; i > 0; i-- ) { + if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && + n[ i - 1 ] == o[ n[i].row - 1 ]) { + + n[ i - 1 ] = { + text: n[ i - 1 ], + row: n[i].row - 1 + }; + o[ n[i].row - 1 ] = { + text: o[ n[i].row - 1 ], + row: i - 1 + }; + } + } + + return { + o: o, + n: n + }; + } + + return function( o, n ) { + o = o.replace( /\s+$/, "" ); + n = n.replace( /\s+$/, "" ); + + var i, pre, + str = "", + out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), + oSpace = o.match(/\s+/g), + nSpace = n.match(/\s+/g); + + if ( oSpace == null ) { + oSpace = [ " " ]; + } + else { + oSpace.push( " " ); + } + + if ( nSpace == null ) { + nSpace = [ " " ]; + } + else { + nSpace.push( " " ); + } + + if ( out.n.length === 0 ) { + for ( i = 0; i < out.o.length; i++ ) { + str += "<del>" + out.o[i] + oSpace[i] + "</del>"; + } + } + else { + if ( out.n[0].text == null ) { + for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { + str += "<del>" + out.o[n] + oSpace[n] + "</del>"; + } + } + + for ( i = 0; i < out.n.length; i++ ) { + if (out.n[i].text == null) { + str += "<ins>" + out.n[i] + nSpace[i] + "</ins>"; + } + else { + // `pre` initialized at top of scope + pre = ""; + + for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { + pre += "<del>" + out.o[n] + oSpace[n] + "</del>"; + } + str += " " + out.n[i].text + nSpace[i] + pre; + } + } + } + + return str; + }; +}()); + +// for CommonJS enviroments, export everything +if ( typeof exports !== "undefined" ) { + extend(exports, QUnit); +} + +// get at whatever the global object is, like window in browsers +}( (function() {return this;}.call()) )); diff --git a/web/src/vendor/benchmark/vendor/requirejs/LICENSE b/web/src/vendor/benchmark/vendor/requirejs/LICENSE new file mode 100644 index 00000000..ffaf3171 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/requirejs/LICENSE @@ -0,0 +1,58 @@ +RequireJS is released under two licenses: new BSD, and MIT. You may pick the +license that best suits your development needs. The text of both licenses are +provided below. + + +The "New" BSD License: +---------------------- + +Copyright (c) 2010-2011, The Dojo Foundation +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the Dojo Foundation nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + + +MIT License +----------- + +Copyright (c) 2010-2011, The Dojo Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/web/src/vendor/benchmark/vendor/requirejs/README.md b/web/src/vendor/benchmark/vendor/requirejs/README.md new file mode 100644 index 00000000..4d3f25e3 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/requirejs/README.md @@ -0,0 +1,51 @@ +# RequireJS + +RequireJS loads plain JavaScript files as well as more defined modules. It is +optimized for in-browser use, including in +[a Web Worker](http://requirejs.org/docs/api.html#webworker), but it can be used +in other JavaScript environments, like Rhino and +[Node](http://requirejs.org/docs/node.html). It implements the +[Asynchronous Module](https://github.com/amdjs/amdjs-api/wiki/AMD) +API. + +RequireJS uses plain script tags to load modules/files, so it should allow for +easy debugging. It can be used +[simply to load existing JavaScript files](http://requirejs.org/docs/api.html#jsfiles), +so you can add it to your existing project without having to re-write your +JavaScript files. + +RequireJS includes [an optimization tool](http://requirejs.org/docs/optimization.html) +you can run as part of your packaging steps for deploying your code. The +optimization tool can combine and minify your JavaScript files to allow for +better performance. + +If the JavaScript file defines a JavaScript module via +[define()](http://requirejs.org/docs/api.html#define), then there are other benefits +RequireJS can offer: [improvements over traditional CommonJS modules](http://requirejs.org/docs/commonjs.html) +and [loading multiple versions](http://requirejs.org/docs/api.html#multiversion) +of a module in a page. RequireJS also has a plugin system that supports features like +[i18n string bundles](http://requirejs.org/docs/api.html#i18n), and +[text file dependencies](http://requirejs.org/docs/api.html#text). + +RequireJS does not have any dependencies on a JavaScript framework. +It is dual-licensed -- new BSD or MIT. + +The standard require.js file is around 5.5KB when minified via Closure Compiler +and gzipped. + +RequireJS works in IE 6+, Firefox 2+, Safari 3.2+, Chrome 3+, and Opera 10+. + +[Latest Release](http://requirejs.org/docs/download.html) + +## Directories + +* **dist**: Scripts and assets to generate the requirejs.org docs, and for +generating a require.js release. +* **docs**: The raw HTML files for the requirejs.org docs. Only includes the +body of each page. Files in **dist** are used to generate a complete HTML page. +* **tests**: Tests for require.js. +* **testBaseUrl.js**: A file used in the tests inside **tests**. Purposely +placed outside the tests directory for testing paths that go outside a baseUrl. +* **updatesubs.sh**: Updates projects that depend on require.js Assumes the +projects are siblings to this directory and have specific names. Useful to +copy require.js to dependent projects easily while in development. diff --git a/web/src/vendor/benchmark/vendor/requirejs/require.js b/web/src/vendor/benchmark/vendor/requirejs/require.js new file mode 100644 index 00000000..34cfe231 --- /dev/null +++ b/web/src/vendor/benchmark/vendor/requirejs/require.js @@ -0,0 +1,2053 @@ +/** vim: et:ts=4:sw=4:sts=4 + * @license RequireJS 2.0.5 Copyright (c) 2010-2012, The Dojo Foundation All Rights Reserved. + * Available via the MIT or new BSD license. + * see: http://github.com/jrburke/requirejs for details + */ +//Not using strict: uneven strict support in browsers, #392, and causes +//problems with requirejs.exec()/transpiler plugins that may not be strict. +/*jslint regexp: true, nomen: true, sloppy: true */ +/*global window, navigator, document, importScripts, jQuery, setTimeout, opera */ + +var requirejs, require, define; +(function (global) { + var req, s, head, baseElement, dataMain, src, + interactiveScript, currentlyAddingScript, mainScript, subPath, + version = '2.0.5', + commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg, + cjsRequireRegExp = /[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g, + jsSuffixRegExp = /\.js$/, + currDirRegExp = /^\.\//, + op = Object.prototype, + ostring = op.toString, + hasOwn = op.hasOwnProperty, + ap = Array.prototype, + aps = ap.slice, + apsp = ap.splice, + isBrowser = !!(typeof window !== 'undefined' && navigator && document), + isWebWorker = !isBrowser && typeof importScripts !== 'undefined', + //PS3 indicates loaded and complete, but need to wait for complete + //specifically. Sequence is 'loading', 'loaded', execution, + // then 'complete'. The UA check is unfortunate, but not sure how + //to feature test w/o causing perf issues. + readyRegExp = isBrowser && navigator.platform === 'PLAYSTATION 3' ? + /^complete$/ : /^(complete|loaded)$/, + defContextName = '_', + //Oh the tragedy, detecting opera. See the usage of isOpera for reason. + isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', + contexts = {}, + cfg = {}, + globalDefQueue = [], + useInteractive = false; + + function isFunction(it) { + return ostring.call(it) === '[object Function]'; + } + + function isArray(it) { + return ostring.call(it) === '[object Array]'; + } + + /** + * Helper function for iterating over an array. If the func returns + * a true value, it will break out of the loop. + */ + function each(ary, func) { + if (ary) { + var i; + for (i = 0; i < ary.length; i += 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + /** + * Helper function for iterating over an array backwards. If the func + * returns a true value, it will break out of the loop. + */ + function eachReverse(ary, func) { + if (ary) { + var i; + for (i = ary.length - 1; i > -1; i -= 1) { + if (ary[i] && func(ary[i], i, ary)) { + break; + } + } + } + } + + function hasProp(obj, prop) { + return hasOwn.call(obj, prop); + } + + /** + * Cycles over properties in an object and calls a function for each + * property value. If the function returns a truthy value, then the + * iteration is stopped. + */ + function eachProp(obj, func) { + var prop; + for (prop in obj) { + if (obj.hasOwnProperty(prop)) { + if (func(obj[prop], prop)) { + break; + } + } + } + } + + /** + * Simple function to mix in properties from source into target, + * but only if target does not already have a property of the same name. + * This is not robust in IE for transferring methods that match + * Object.prototype names, but the uses of mixin here seem unlikely to + * trigger a problem related to that. + */ + function mixin(target, source, force, deepStringMixin) { + if (source) { + eachProp(source, function (value, prop) { + if (force || !hasProp(target, prop)) { + if (deepStringMixin && typeof value !== 'string') { + if (!target[prop]) { + target[prop] = {}; + } + mixin(target[prop], value, force, deepStringMixin); + } else { + target[prop] = value; + } + } + }); + } + return target; + } + + //Similar to Function.prototype.bind, but the 'this' object is specified + //first, since it is easier to read/figure out what 'this' will be. + function bind(obj, fn) { + return function () { + return fn.apply(obj, arguments); + }; + } + + function scripts() { + return document.getElementsByTagName('script'); + } + + //Allow getting a global that expressed in + //dot notation, like 'a.b.c'. + function getGlobal(value) { + if (!value) { + return value; + } + var g = global; + each(value.split('.'), function (part) { + g = g[part]; + }); + return g; + } + + function makeContextModuleFunc(func, relMap, enableBuildCallback) { + return function () { + //A version of a require function that passes a moduleName + //value for items that may need to + //look up paths relative to the moduleName + var args = aps.call(arguments, 0), lastArg; + if (enableBuildCallback && + isFunction((lastArg = args[args.length - 1]))) { + lastArg.__requireJsBuild = true; + } + args.push(relMap); + return func.apply(null, args); + }; + } + + function addRequireMethods(req, context, relMap) { + each([ + ['toUrl'], + ['undef'], + ['defined', 'requireDefined'], + ['specified', 'requireSpecified'] + ], function (item) { + var prop = item[1] || item[0]; + req[item[0]] = context ? makeContextModuleFunc(context[prop], relMap) : + //If no context, then use default context. Reference from + //contexts instead of early binding to default context, so + //that during builds, the latest instance of the default + //context with its config gets used. + function () { + var ctx = contexts[defContextName]; + return ctx[prop].apply(ctx, arguments); + }; + }); + } + + /** + * Constructs an error with a pointer to an URL with more information. + * @param {String} id the error ID that maps to an ID on a web page. + * @param {String} message human readable error. + * @param {Error} [err] the original error, if there is one. + * + * @returns {Error} + */ + function makeError(id, msg, err, requireModules) { + var e = new Error(msg + '\nhttp://requirejs.org/docs/errors.html#' + id); + e.requireType = id; + e.requireModules = requireModules; + if (err) { + e.originalError = err; + } + return e; + } + + if (typeof define !== 'undefined') { + //If a define is already in play via another AMD loader, + //do not overwrite. + return; + } + + if (typeof requirejs !== 'undefined') { + if (isFunction(requirejs)) { + //Do not overwrite and existing requirejs instance. + return; + } + cfg = requirejs; + requirejs = undefined; + } + + //Allow for a require config object + if (typeof require !== 'undefined' && !isFunction(require)) { + //assume it is a config object. + cfg = require; + require = undefined; + } + + function newContext(contextName) { + var inCheckLoaded, Module, context, handlers, + checkLoadedTimeoutId, + config = { + waitSeconds: 7, + baseUrl: './', + paths: {}, + pkgs: {}, + shim: {} + }, + registry = {}, + undefEvents = {}, + defQueue = [], + defined = {}, + urlFetched = {}, + requireCounter = 1, + unnormalizedCounter = 1, + //Used to track the order in which modules + //should be executed, by the order they + //load. Important for consistent cycle resolution + //behavior. + waitAry = []; + + /** + * Trims the . and .. from an array of path segments. + * It will keep a leading path segment if a .. will become + * the first path segment, to help with module name lookups, + * which act like paths, but can be remapped. But the end result, + * all paths that use this function should look normalized. + * NOTE: this method MODIFIES the input array. + * @param {Array} ary the array of path segments. + */ + function trimDots(ary) { + var i, part; + for (i = 0; ary[i]; i += 1) { + part = ary[i]; + if (part === '.') { + ary.splice(i, 1); + i -= 1; + } else if (part === '..') { + if (i === 1 && (ary[2] === '..' || ary[0] === '..')) { + //End of the line. Keep at least one non-dot + //path segment at the front so it can be mapped + //correctly to disk. Otherwise, there is likely + //no path mapping for a path starting with '..'. + //This can still fail, but catches the most reasonable + //uses of .. + break; + } else if (i > 0) { + ary.splice(i - 1, 2); + i -= 2; + } + } + } + } + + /** + * Given a relative module name, like ./something, normalize it to + * a real name that can be mapped to a path. + * @param {String} name the relative name + * @param {String} baseName a real name that the name arg is relative + * to. + * @param {Boolean} applyMap apply the map config to the value. Should + * only be done if this normalization is for a dependency ID. + * @returns {String} normalized name + */ + function normalize(name, baseName, applyMap) { + var pkgName, pkgConfig, mapValue, nameParts, i, j, nameSegment, + foundMap, foundI, foundStarMap, starI, + baseParts = baseName && baseName.split('/'), + normalizedBaseParts = baseParts, + map = config.map, + starMap = map && map['*']; + + //Adjust any relative paths. + if (name && name.charAt(0) === '.') { + //If have a base name, try to normalize against it, + //otherwise, assume it is a top-level require that will + //be relative to baseUrl in the end. + if (baseName) { + if (config.pkgs[baseName]) { + //If the baseName is a package name, then just treat it as one + //name to concat the name with. + normalizedBaseParts = baseParts = [baseName]; + } else { + //Convert baseName to array, and lop off the last part, + //so that . matches that 'directory' and not name of the baseName's + //module. For instance, baseName of 'one/two/three', maps to + //'one/two/three.js', but we want the directory, 'one/two' for + //this normalization. + normalizedBaseParts = baseParts.slice(0, baseParts.length - 1); + } + + name = normalizedBaseParts.concat(name.split('/')); + trimDots(name); + + //Some use of packages may use a . path to reference the + //'main' module name, so normalize for that. + pkgConfig = config.pkgs[(pkgName = name[0])]; + name = name.join('/'); + if (pkgConfig && name === pkgName + '/' + pkgConfig.main) { + name = pkgName; + } + } else if (name.indexOf('./') === 0) { + // No baseName, so this is ID is resolved relative + // to baseUrl, pull off the leading dot. + name = name.substring(2); + } + } + + //Apply map config if available. + if (applyMap && (baseParts || starMap) && map) { + nameParts = name.split('/'); + + for (i = nameParts.length; i > 0; i -= 1) { + nameSegment = nameParts.slice(0, i).join('/'); + + if (baseParts) { + //Find the longest baseName segment match in the config. + //So, do joins on the biggest to smallest lengths of baseParts. + for (j = baseParts.length; j > 0; j -= 1) { + mapValue = map[baseParts.slice(0, j).join('/')]; + + //baseName segment has config, find if it has one for + //this name. + if (mapValue) { + mapValue = mapValue[nameSegment]; + if (mapValue) { + //Match, update name to the new value. + foundMap = mapValue; + foundI = i; + break; + } + } + } + } + + if (foundMap) { + break; + } + + //Check for a star map match, but just hold on to it, + //if there is a shorter segment match later in a matching + //config, then favor over this star map. + if (!foundStarMap && starMap && starMap[nameSegment]) { + foundStarMap = starMap[nameSegment]; + starI = i; + } + } + + if (!foundMap && foundStarMap) { + foundMap = foundStarMap; + foundI = starI; + } + + if (foundMap) { + nameParts.splice(0, foundI, foundMap); + name = nameParts.join('/'); + } + } + + return name; + } + + function removeScript(name) { + if (isBrowser) { + each(scripts(), function (scriptNode) { + if (scriptNode.getAttribute('data-requiremodule') === name && + scriptNode.getAttribute('data-requirecontext') === context.contextName) { + scriptNode.parentNode.removeChild(scriptNode); + return true; + } + }); + } + } + + function hasPathFallback(id) { + var pathConfig = config.paths[id]; + if (pathConfig && isArray(pathConfig) && pathConfig.length > 1) { + removeScript(id); + //Pop off the first array value, since it failed, and + //retry + pathConfig.shift(); + context.undef(id); + context.require([id]); + return true; + } + } + + /** + * Creates a module mapping that includes plugin prefix, module + * name, and path. If parentModuleMap is provided it will + * also normalize the name via require.normalize() + * + * @param {String} name the module name + * @param {String} [parentModuleMap] parent module map + * for the module name, used to resolve relative names. + * @param {Boolean} isNormalized: is the ID already normalized. + * This is true if this call is done for a define() module ID. + * @param {Boolean} applyMap: apply the map config to the ID. + * Should only be true if this map is for a dependency. + * + * @returns {Object} + */ + function makeModuleMap(name, parentModuleMap, isNormalized, applyMap) { + var url, pluginModule, suffix, + index = name ? name.indexOf('!') : -1, + prefix = null, + parentName = parentModuleMap ? parentModuleMap.name : null, + originalName = name, + isDefine = true, + normalizedName = ''; + + //If no name, then it means it is a require call, generate an + //internal name. + if (!name) { + isDefine = false; + name = '_@r' + (requireCounter += 1); + } + + if (index !== -1) { + prefix = name.substring(0, index); + name = name.substring(index + 1, name.length); + } + + if (prefix) { + prefix = normalize(prefix, parentName, applyMap); + pluginModule = defined[prefix]; + } + + //Account for relative paths if there is a base name. + if (name) { + if (prefix) { + if (pluginModule && pluginModule.normalize) { + //Plugin is loaded, use its normalize method. + normalizedName = pluginModule.normalize(name, function (name) { + return normalize(name, parentName, applyMap); + }); + } else { + normalizedName = normalize(name, parentName, applyMap); + } + } else { + //A regular module. + normalizedName = normalize(name, parentName, applyMap); + url = context.nameToUrl(normalizedName); + } + } + + //If the id is a plugin id that cannot be determined if it needs + //normalization, stamp it with a unique ID so two matching relative + //ids that may conflict can be separate. + suffix = prefix && !pluginModule && !isNormalized ? + '_unnormalized' + (unnormalizedCounter += 1) : + ''; + + return { + prefix: prefix, + name: normalizedName, + parentMap: parentModuleMap, + unnormalized: !!suffix, + url: url, + originalName: originalName, + isDefine: isDefine, + id: (prefix ? + prefix + '!' + normalizedName : + normalizedName) + suffix + }; + } + + function getModule(depMap) { + var id = depMap.id, + mod = registry[id]; + + if (!mod) { + mod = registry[id] = new context.Module(depMap); + } + + return mod; + } + + function on(depMap, name, fn) { + var id = depMap.id, + mod = registry[id]; + + if (hasProp(defined, id) && + (!mod || mod.defineEmitComplete)) { + if (name === 'defined') { + fn(defined[id]); + } + } else { + getModule(depMap).on(name, fn); + } + } + + function onError(err, errback) { + var ids = err.requireModules, + notified = false; + + if (errback) { + errback(err); + } else { + each(ids, function (id) { + var mod = registry[id]; + if (mod) { + //Set error on module, so it skips timeout checks. + mod.error = err; + if (mod.events.error) { + notified = true; + mod.emit('error', err); + } + } + }); + + if (!notified) { + req.onError(err); + } + } + } + + /** + * Internal method to transfer globalQueue items to this context's + * defQueue. + */ + function takeGlobalQueue() { + //Push all the globalDefQueue items into the context's defQueue + if (globalDefQueue.length) { + //Array splice in the values since the context code has a + //local var ref to defQueue, so cannot just reassign the one + //on context. + apsp.apply(defQueue, + [defQueue.length - 1, 0].concat(globalDefQueue)); + globalDefQueue = []; + } + } + + /** + * Helper function that creates a require function object to give to + * modules that ask for it as a dependency. It needs to be specific + * per module because of the implication of path mappings that may + * need to be relative to the module name. + */ + function makeRequire(mod, enableBuildCallback, altRequire) { + var relMap = mod && mod.map, + modRequire = makeContextModuleFunc(altRequire || context.require, + relMap, + enableBuildCallback); + + addRequireMethods(modRequire, context, relMap); + modRequire.isBrowser = isBrowser; + + return modRequire; + } + + handlers = { + 'require': function (mod) { + return makeRequire(mod); + }, + 'exports': function (mod) { + mod.usingExports = true; + if (mod.map.isDefine) { + return (mod.exports = defined[mod.map.id] = {}); + } + }, + 'module': function (mod) { + return (mod.module = { + id: mod.map.id, + uri: mod.map.url, + config: function () { + return (config.config && config.config[mod.map.id]) || {}; + }, + exports: defined[mod.map.id] + }); + } + }; + + function removeWaiting(id) { + //Clean up machinery used for waiting modules. + delete registry[id]; + + each(waitAry, function (mod, i) { + if (mod.map.id === id) { + waitAry.splice(i, 1); + if (!mod.defined) { + context.waitCount -= 1; + } + return true; + } + }); + } + + function findCycle(mod, traced) { + var id = mod.map.id, + depArray = mod.depMaps, + foundModule; + + //Do not bother with unitialized modules or not yet enabled + //modules. + if (!mod.inited) { + return; + } + + //Found the cycle. + if (traced[id]) { + return mod; + } + + traced[id] = true; + + //Trace through the dependencies. + each(depArray, function (depMap) { + var depId = depMap.id, + depMod = registry[depId]; + + if (!depMod) { + return; + } + + if (!depMod.inited || !depMod.enabled) { + //Dependency is not inited, so this cannot + //be used to determine a cycle. + foundModule = null; + delete traced[id]; + return true; + } + + //mixin traced to a new object for each dependency, so that + //sibling dependencies in this object to not generate a + //false positive match on a cycle. Ideally an Object.create + //type of prototype delegation would be used here, but + //optimizing for file size vs. execution speed since hopefully + //the trees are small for circular dependency scans relative + //to the full app perf. + return (foundModule = findCycle(depMod, mixin({}, traced))); + }); + + return foundModule; + } + + function forceExec(mod, traced, uninited) { + var id = mod.map.id, + depArray = mod.depMaps; + + if (!mod.inited || !mod.map.isDefine) { + return; + } + + if (traced[id]) { + return defined[id]; + } + + traced[id] = mod; + + each(depArray, function (depMap) { + var depId = depMap.id, + depMod = registry[depId], + value; + + if (handlers[depId]) { + return; + } + + if (depMod) { + if (!depMod.inited || !depMod.enabled) { + //Dependency is not inited, + //so this module cannot be + //given a forced value yet. + uninited[id] = true; + return; + } + + //Get the value for the current dependency + value = forceExec(depMod, traced, uninited); + + //Even with forcing it may not be done, + //in particular if the module is waiting + //on a plugin resource. + if (!uninited[depId]) { + mod.defineDepById(depId, value); + } + } + }); + + mod.check(true); + + return defined[id]; + } + + function modCheck(mod) { + mod.check(); + } + + function checkLoaded() { + var map, modId, err, usingPathFallback, + waitInterval = config.waitSeconds * 1000, + //It is possible to disable the wait interval by using waitSeconds of 0. + expired = waitInterval && (context.startTime + waitInterval) < new Date().getTime(), + noLoads = [], + stillLoading = false, + needCycleCheck = true; + + //Do not bother if this call was a result of a cycle break. + if (inCheckLoaded) { + return; + } + + inCheckLoaded = true; + + //Figure out the state of all the modules. + eachProp(registry, function (mod) { + map = mod.map; + modId = map.id; + + //Skip things that are not enabled or in error state. + if (!mod.enabled) { + return; + } + + if (!mod.error) { + //If the module should be executed, and it has not + //been inited and time is up, remember it. + if (!mod.inited && expired) { + if (hasPathFallback(modId)) { + usingPathFallback = true; + stillLoading = true; + } else { + noLoads.push(modId); + removeScript(modId); + } + } else if (!mod.inited && mod.fetched && map.isDefine) { + stillLoading = true; + if (!map.prefix) { + //No reason to keep looking for unfinished + //loading. If the only stillLoading is a + //plugin resource though, keep going, + //because it may be that a plugin resource + //is waiting on a non-plugin cycle. + return (needCycleCheck = false); + } + } + } + }); + + if (expired && noLoads.length) { + //If wait time expired, throw error of unloaded modules. + err = makeError('timeout', 'Load timeout for modules: ' + noLoads, null, noLoads); + err.contextName = context.contextName; + return onError(err); + } + + //Not expired, check for a cycle. + if (needCycleCheck) { + + each(waitAry, function (mod) { + if (mod.defined) { + return; + } + + var cycleMod = findCycle(mod, {}), + traced = {}; + + if (cycleMod) { + forceExec(cycleMod, traced, {}); + + //traced modules may have been + //removed from the registry, but + //their listeners still need to + //be called. + eachProp(traced, modCheck); + } + }); + + //Now that dependencies have + //been satisfied, trigger the + //completion check that then + //notifies listeners. + eachProp(registry, modCheck); + } + + //If still waiting on loads, and the waiting load is something + //other than a plugin resource, or there are still outstanding + //scripts, then just try back later. + if ((!expired || usingPathFallback) && stillLoading) { + //Something is still waiting to load. Wait for it, but only + //if a timeout is not already in effect. + if ((isBrowser || isWebWorker) && !checkLoadedTimeoutId) { + checkLoadedTimeoutId = setTimeout(function () { + checkLoadedTimeoutId = 0; + checkLoaded(); + }, 50); + } + } + + inCheckLoaded = false; + } + + Module = function (map) { + this.events = undefEvents[map.id] || {}; + this.map = map; + this.shim = config.shim[map.id]; + this.depExports = []; + this.depMaps = []; + this.depMatched = []; + this.pluginMaps = {}; + this.depCount = 0; + + /* this.exports this.factory + this.depMaps = [], + this.enabled, this.fetched + */ + }; + + Module.prototype = { + init: function (depMaps, factory, errback, options) { + options = options || {}; + + //Do not do more inits if already done. Can happen if there + //are multiple define calls for the same module. That is not + //a normal, common case, but it is also not unexpected. + if (this.inited) { + return; + } + + this.factory = factory; + + if (errback) { + //Register for errors on this module. + this.on('error', errback); + } else if (this.events.error) { + //If no errback already, but there are error listeners + //on this module, set up an errback to pass to the deps. + errback = bind(this, function (err) { + this.emit('error', err); + }); + } + + //Do a copy of the dependency array, so that + //source inputs are not modified. For example + //"shim" deps are passed in here directly, and + //doing a direct modification of the depMaps array + //would affect that config. + this.depMaps = depMaps && depMaps.slice(0); + this.depMaps.rjsSkipMap = depMaps.rjsSkipMap; + + this.errback = errback; + + //Indicate this module has be initialized + this.inited = true; + + this.ignore = options.ignore; + + //Could have option to init this module in enabled mode, + //or could have been previously marked as enabled. However, + //the dependencies are not known until init is called. So + //if enabled previously, now trigger dependencies as enabled. + if (options.enabled || this.enabled) { + //Enable this module and dependencies. + //Will call this.check() + this.enable(); + } else { + this.check(); + } + }, + + defineDepById: function (id, depExports) { + var i; + + //Find the index for this dependency. + each(this.depMaps, function (map, index) { + if (map.id === id) { + i = index; + return true; + } + }); + + return this.defineDep(i, depExports); + }, + + defineDep: function (i, depExports) { + //Because of cycles, defined callback for a given + //export can be called more than once. + if (!this.depMatched[i]) { + this.depMatched[i] = true; + this.depCount -= 1; + this.depExports[i] = depExports; + } + }, + + fetch: function () { + if (this.fetched) { + return; + } + this.fetched = true; + + context.startTime = (new Date()).getTime(); + + var map = this.map; + + //If the manager is for a plugin managed resource, + //ask the plugin to load it now. + if (this.shim) { + makeRequire(this, true)(this.shim.deps || [], bind(this, function () { + return map.prefix ? this.callPlugin() : this.load(); + })); + } else { + //Regular dependency. + return map.prefix ? this.callPlugin() : this.load(); + } + }, + + load: function () { + var url = this.map.url; + + //Regular dependency. + if (!urlFetched[url]) { + urlFetched[url] = true; + context.load(this.map.id, url); + } + }, + + /** + * Checks is the module is ready to define itself, and if so, + * define it. If the silent argument is true, then it will just + * define, but not notify listeners, and not ask for a context-wide + * check of all loaded modules. That is useful for cycle breaking. + */ + check: function (silent) { + if (!this.enabled || this.enabling) { + return; + } + + var err, cjsModule, + id = this.map.id, + depExports = this.depExports, + exports = this.exports, + factory = this.factory; + + if (!this.inited) { + this.fetch(); + } else if (this.error) { + this.emit('error', this.error); + } else if (!this.defining) { + //The factory could trigger another require call + //that would result in checking this module to + //define itself again. If already in the process + //of doing that, skip this work. + this.defining = true; + + if (this.depCount < 1 && !this.defined) { + if (isFunction(factory)) { + //If there is an error listener, favor passing + //to that instead of throwing an error. + if (this.events.error) { + try { + exports = context.execCb(id, factory, depExports, exports); + } catch (e) { + err = e; + } + } else { + exports = context.execCb(id, factory, depExports, exports); + } + + if (this.map.isDefine) { + //If setting exports via 'module' is in play, + //favor that over return value and exports. After that, + //favor a non-undefined return value over exports use. + cjsModule = this.module; + if (cjsModule && + cjsModule.exports !== undefined && + //Make sure it is not already the exports value + cjsModule.exports !== this.exports) { + exports = cjsModule.exports; + } else if (exports === undefined && this.usingExports) { + //exports already set the defined value. + exports = this.exports; + } + } + + if (err) { + err.requireMap = this.map; + err.requireModules = [this.map.id]; + err.requireType = 'define'; + return onError((this.error = err)); + } + + } else { + //Just a literal value + exports = factory; + } + + this.exports = exports; + + if (this.map.isDefine && !this.ignore) { + defined[id] = exports; + + if (req.onResourceLoad) { + req.onResourceLoad(context, this.map, this.depMaps); + } + } + + //Clean up + delete registry[id]; + + this.defined = true; + context.waitCount -= 1; + if (context.waitCount === 0) { + //Clear the wait array used for cycles. + waitAry = []; + } + } + + //Finished the define stage. Allow calling check again + //to allow define notifications below in the case of a + //cycle. + this.defining = false; + + if (!silent) { + if (this.defined && !this.defineEmitted) { + this.defineEmitted = true; + this.emit('defined', this.exports); + this.defineEmitComplete = true; + } + } + } + }, + + callPlugin: function () { + var map = this.map, + id = map.id, + pluginMap = makeModuleMap(map.prefix, null, false, true); + + on(pluginMap, 'defined', bind(this, function (plugin) { + var load, normalizedMap, normalizedMod, + name = this.map.name, + parentName = this.map.parentMap ? this.map.parentMap.name : null; + + //If current map is not normalized, wait for that + //normalized name to load instead of continuing. + if (this.map.unnormalized) { + //Normalize the ID if the plugin allows it. + if (plugin.normalize) { + name = plugin.normalize(name, function (name) { + return normalize(name, parentName, true); + }) || ''; + } + + normalizedMap = makeModuleMap(map.prefix + '!' + name, + this.map.parentMap, + false, + true); + on(normalizedMap, + 'defined', bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true, + ignore: true + }); + })); + normalizedMod = registry[normalizedMap.id]; + if (normalizedMod) { + if (this.events.error) { + normalizedMod.on('error', bind(this, function (err) { + this.emit('error', err); + })); + } + normalizedMod.enable(); + } + + return; + } + + load = bind(this, function (value) { + this.init([], function () { return value; }, null, { + enabled: true + }); + }); + + load.error = bind(this, function (err) { + this.inited = true; + this.error = err; + err.requireModules = [id]; + + //Remove temp unnormalized modules for this module, + //since they will never be resolved otherwise now. + eachProp(registry, function (mod) { + if (mod.map.id.indexOf(id + '_unnormalized') === 0) { + removeWaiting(mod.map.id); + } + }); + + onError(err); + }); + + //Allow plugins to load other code without having to know the + //context or how to 'complete' the load. + load.fromText = function (moduleName, text) { + /*jslint evil: true */ + var hasInteractive = useInteractive; + + //Turn off interactive script matching for IE for any define + //calls in the text, then turn it back on at the end. + if (hasInteractive) { + useInteractive = false; + } + + //Prime the system by creating a module instance for + //it. + getModule(makeModuleMap(moduleName)); + + req.exec(text); + + if (hasInteractive) { + useInteractive = true; + } + + //Support anonymous modules. + context.completeLoad(moduleName); + }; + + //Use parentName here since the plugin's name is not reliable, + //could be some weird string with no path that actually wants to + //reference the parentName's path. + plugin.load(map.name, makeRequire(map.parentMap, true, function (deps, cb, er) { + deps.rjsSkipMap = true; + return context.require(deps, cb, er); + }), load, config); + })); + + context.enable(pluginMap, this); + this.pluginMaps[pluginMap.id] = pluginMap; + }, + + enable: function () { + this.enabled = true; + + if (!this.waitPushed) { + waitAry.push(this); + context.waitCount += 1; + this.waitPushed = true; + } + + //Set flag mentioning that the module is enabling, + //so that immediate calls to the defined callbacks + //for dependencies do not trigger inadvertent load + //with the depCount still being zero. + this.enabling = true; + + //Enable each dependency + each(this.depMaps, bind(this, function (depMap, i) { + var id, mod, handler; + + if (typeof depMap === 'string') { + //Dependency needs to be converted to a depMap + //and wired up to this module. + depMap = makeModuleMap(depMap, + (this.map.isDefine ? this.map : this.map.parentMap), + false, + !this.depMaps.rjsSkipMap); + this.depMaps[i] = depMap; + + handler = handlers[depMap.id]; + + if (handler) { + this.depExports[i] = handler(this); + return; + } + + this.depCount += 1; + + on(depMap, 'defined', bind(this, function (depExports) { + this.defineDep(i, depExports); + this.check(); + })); + + if (this.errback) { + on(depMap, 'error', this.errback); + } + } + + id = depMap.id; + mod = registry[id]; + + //Skip special modules like 'require', 'exports', 'module' + //Also, don't call enable if it is already enabled, + //important in circular dependency cases. + if (!handlers[id] && mod && !mod.enabled) { + context.enable(depMap, this); + } + })); + + //Enable each plugin that is used in + //a dependency + eachProp(this.pluginMaps, bind(this, function (pluginMap) { + var mod = registry[pluginMap.id]; + if (mod && !mod.enabled) { + context.enable(pluginMap, this); + } + })); + + this.enabling = false; + + this.check(); + }, + + on: function (name, cb) { + var cbs = this.events[name]; + if (!cbs) { + cbs = this.events[name] = []; + } + cbs.push(cb); + }, + + emit: function (name, evt) { + each(this.events[name], function (cb) { + cb(evt); + }); + if (name === 'error') { + //Now that the error handler was triggered, remove + //the listeners, since this broken Module instance + //can stay around for a while in the registry/waitAry. + delete this.events[name]; + } + } + }; + + function callGetModule(args) { + getModule(makeModuleMap(args[0], null, true)).init(args[1], args[2]); + } + + function removeListener(node, func, name, ieName) { + //Favor detachEvent because of IE9 + //issue, see attachEvent/addEventListener comment elsewhere + //in this file. + if (node.detachEvent && !isOpera) { + //Probably IE. If not it will throw an error, which will be + //useful to know. + if (ieName) { + node.detachEvent(ieName, func); + } + } else { + node.removeEventListener(name, func, false); + } + } + + /** + * Given an event from a script node, get the requirejs info from it, + * and then removes the event listeners on the node. + * @param {Event} evt + * @returns {Object} + */ + function getScriptData(evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + var node = evt.currentTarget || evt.srcElement; + + //Remove the listeners once here. + removeListener(node, context.onScriptLoad, 'load', 'onreadystatechange'); + removeListener(node, context.onScriptError, 'error'); + + return { + node: node, + id: node && node.getAttribute('data-requiremodule') + }; + } + + return (context = { + config: config, + contextName: contextName, + registry: registry, + defined: defined, + urlFetched: urlFetched, + waitCount: 0, + defQueue: defQueue, + Module: Module, + makeModuleMap: makeModuleMap, + + /** + * Set a configuration for the context. + * @param {Object} cfg config object to integrate. + */ + configure: function (cfg) { + //Make sure the baseUrl ends in a slash. + if (cfg.baseUrl) { + if (cfg.baseUrl.charAt(cfg.baseUrl.length - 1) !== '/') { + cfg.baseUrl += '/'; + } + } + + //Save off the paths and packages since they require special processing, + //they are additive. + var pkgs = config.pkgs, + shim = config.shim, + paths = config.paths, + map = config.map; + + //Mix in the config values, favoring the new values over + //existing ones in context.config. + mixin(config, cfg, true); + + //Merge paths. + config.paths = mixin(paths, cfg.paths, true); + + //Merge map + if (cfg.map) { + config.map = mixin(map || {}, cfg.map, true, true); + } + + //Merge shim + if (cfg.shim) { + eachProp(cfg.shim, function (value, id) { + //Normalize the structure + if (isArray(value)) { + value = { + deps: value + }; + } + if (value.exports && !value.exports.__buildReady) { + value.exports = context.makeShimExports(value.exports); + } + shim[id] = value; + }); + config.shim = shim; + } + + //Adjust packages if necessary. + if (cfg.packages) { + each(cfg.packages, function (pkgObj) { + var location; + + pkgObj = typeof pkgObj === 'string' ? { name: pkgObj } : pkgObj; + location = pkgObj.location; + + //Create a brand new object on pkgs, since currentPackages can + //be passed in again, and config.pkgs is the internal transformed + //state for all package configs. + pkgs[pkgObj.name] = { + name: pkgObj.name, + location: location || pkgObj.name, + //Remove leading dot in main, so main paths are normalized, + //and remove any trailing .js, since different package + //envs have different conventions: some use a module name, + //some use a file name. + main: (pkgObj.main || 'main') + .replace(currDirRegExp, '') + .replace(jsSuffixRegExp, '') + }; + }); + + //Done with modifications, assing packages back to context config + config.pkgs = pkgs; + } + + //If there are any "waiting to execute" modules in the registry, + //update the maps for them, since their info, like URLs to load, + //may have changed. + eachProp(registry, function (mod, id) { + //If module already has init called, since it is too + //late to modify them, and ignore unnormalized ones + //since they are transient. + if (!mod.inited && !mod.map.unnormalized) { + mod.map = makeModuleMap(id); + } + }); + + //If a deps array or a config callback is specified, then call + //require with those args. This is useful when require is defined as a + //config object before require.js is loaded. + if (cfg.deps || cfg.callback) { + context.require(cfg.deps || [], cfg.callback); + } + }, + + makeShimExports: function (exports) { + var func; + if (typeof exports === 'string') { + func = function () { + return getGlobal(exports); + }; + //Save the exports for use in nodefine checking. + func.exports = exports; + return func; + } else { + return function () { + return exports.apply(global, arguments); + }; + } + }, + + requireDefined: function (id, relMap) { + return hasProp(defined, makeModuleMap(id, relMap, false, true).id); + }, + + requireSpecified: function (id, relMap) { + id = makeModuleMap(id, relMap, false, true).id; + return hasProp(defined, id) || hasProp(registry, id); + }, + + require: function (deps, callback, errback, relMap) { + var moduleName, id, map, requireMod, args; + if (typeof deps === 'string') { + if (isFunction(callback)) { + //Invalid call + return onError(makeError('requireargs', 'Invalid require call'), errback); + } + + //Synchronous access to one module. If require.get is + //available (as in the Node adapter), prefer that. + //In this case deps is the moduleName and callback is + //the relMap + if (req.get) { + return req.get(context, deps, callback); + } + + //Just return the module wanted. In this scenario, the + //second arg (if passed) is just the relMap. + moduleName = deps; + relMap = callback; + + //Normalize module name, if it contains . or .. + map = makeModuleMap(moduleName, relMap, false, true); + id = map.id; + + if (!hasProp(defined, id)) { + return onError(makeError('notloaded', 'Module name "' + + id + + '" has not been loaded yet for context: ' + + contextName)); + } + return defined[id]; + } + + //Callback require. Normalize args. if callback or errback is + //not a function, it means it is a relMap. Test errback first. + if (errback && !isFunction(errback)) { + relMap = errback; + errback = undefined; + } + if (callback && !isFunction(callback)) { + relMap = callback; + callback = undefined; + } + + //Any defined modules in the global queue, intake them now. + takeGlobalQueue(); + + //Make sure any remaining defQueue items get properly processed. + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + return onError(makeError('mismatch', 'Mismatched anonymous define() module: ' + args[args.length - 1])); + } else { + //args are id, deps, factory. Should be normalized by the + //define() function. + callGetModule(args); + } + } + + //Mark all the dependencies as needing to be loaded. + requireMod = getModule(makeModuleMap(null, relMap)); + + requireMod.init(deps, callback, errback, { + enabled: true + }); + + checkLoaded(); + + return context.require; + }, + + undef: function (id) { + //Bind any waiting define() calls to this context, + //fix for #408 + takeGlobalQueue(); + + var map = makeModuleMap(id, null, true), + mod = registry[id]; + + delete defined[id]; + delete urlFetched[map.url]; + delete undefEvents[id]; + + if (mod) { + //Hold on to listeners in case the + //module will be attempted to be reloaded + //using a different config. + if (mod.events.defined) { + undefEvents[id] = mod.events; + } + + removeWaiting(id); + } + }, + + /** + * Called to enable a module if it is still in the registry + * awaiting enablement. parent module is passed in for context, + * used by the optimizer. + */ + enable: function (depMap, parent) { + var mod = registry[depMap.id]; + if (mod) { + getModule(depMap).enable(); + } + }, + + /** + * Internal method used by environment adapters to complete a load event. + * A load event could be a script load or just a load pass from a synchronous + * load call. + * @param {String} moduleName the name of the module to potentially complete. + */ + completeLoad: function (moduleName) { + var found, args, mod, + shim = config.shim[moduleName] || {}, + shExports = shim.exports && shim.exports.exports; + + takeGlobalQueue(); + + while (defQueue.length) { + args = defQueue.shift(); + if (args[0] === null) { + args[0] = moduleName; + //If already found an anonymous module and bound it + //to this name, then this is some other anon module + //waiting for its completeLoad to fire. + if (found) { + break; + } + found = true; + } else if (args[0] === moduleName) { + //Found matching define call for this script! + found = true; + } + + callGetModule(args); + } + + //Do this after the cycle of callGetModule in case the result + //of those calls/init calls changes the registry. + mod = registry[moduleName]; + + if (!found && !defined[moduleName] && mod && !mod.inited) { + if (config.enforceDefine && (!shExports || !getGlobal(shExports))) { + if (hasPathFallback(moduleName)) { + return; + } else { + return onError(makeError('nodefine', + 'No define call for ' + moduleName, + null, + [moduleName])); + } + } else { + //A script that does not call define(), so just simulate + //the call for it. + callGetModule([moduleName, (shim.deps || []), shim.exports]); + } + } + + checkLoaded(); + }, + + /** + * Converts a module name + .extension into an URL path. + * *Requires* the use of a module name. It does not support using + * plain URLs like nameToUrl. + */ + toUrl: function (moduleNamePlusExt, relModuleMap) { + var index = moduleNamePlusExt.lastIndexOf('.'), + ext = null; + + if (index !== -1) { + ext = moduleNamePlusExt.substring(index, moduleNamePlusExt.length); + moduleNamePlusExt = moduleNamePlusExt.substring(0, index); + } + + return context.nameToUrl(normalize(moduleNamePlusExt, relModuleMap && relModuleMap.id, true), + ext); + }, + + /** + * Converts a module name to a file path. Supports cases where + * moduleName may actually be just an URL. + * Note that it **does not** call normalize on the moduleName, + * it is assumed to have already been normalized. This is an + * internal API, not a public one. Use toUrl for the public API. + */ + nameToUrl: function (moduleName, ext) { + var paths, pkgs, pkg, pkgPath, syms, i, parentModule, url, + parentPath; + + //If a colon is in the URL, it indicates a protocol is used and it is just + //an URL to a file, or if it starts with a slash, contains a query arg (i.e. ?) + //or ends with .js, then assume the user meant to use an url and not a module id. + //The slash is important for protocol-less URLs as well as full paths. + if (req.jsExtRegExp.test(moduleName)) { + //Just a plain path, not module name lookup, so just return it. + //Add extension if it is included. This is a bit wonky, only non-.js things pass + //an extension, this method probably needs to be reworked. + url = moduleName + (ext || ''); + } else { + //A module that needs to be converted to a path. + paths = config.paths; + pkgs = config.pkgs; + + syms = moduleName.split('/'); + //For each module name segment, see if there is a path + //registered for it. Start with most specific name + //and work up from it. + for (i = syms.length; i > 0; i -= 1) { + parentModule = syms.slice(0, i).join('/'); + pkg = pkgs[parentModule]; + parentPath = paths[parentModule]; + if (parentPath) { + //If an array, it means there are a few choices, + //Choose the one that is desired + if (isArray(parentPath)) { + parentPath = parentPath[0]; + } + syms.splice(0, i, parentPath); + break; + } else if (pkg) { + //If module name is just the package name, then looking + //for the main module. + if (moduleName === pkg.name) { + pkgPath = pkg.location + '/' + pkg.main; + } else { + pkgPath = pkg.location; + } + syms.splice(0, i, pkgPath); + break; + } + } + + //Join the path parts together, then figure out if baseUrl is needed. + url = syms.join('/'); + url += (ext || (/\?/.test(url) ? '' : '.js')); + url = (url.charAt(0) === '/' || url.match(/^[\w\+\.\-]+:/) ? '' : config.baseUrl) + url; + } + + return config.urlArgs ? url + + ((url.indexOf('?') === -1 ? '?' : '&') + + config.urlArgs) : url; + }, + + //Delegates to req.load. Broken out as a separate function to + //allow overriding in the optimizer. + load: function (id, url) { + req.load(context, id, url); + }, + + /** + * Executes a module callack function. Broken out as a separate function + * solely to allow the build system to sequence the files in the built + * layer in the right sequence. + * + * @private + */ + execCb: function (name, callback, args, exports) { + return callback.apply(exports, args); + }, + + /** + * callback for script loads, used to check status of loading. + * + * @param {Event} evt the event from the browser for the script + * that was loaded. + */ + onScriptLoad: function (evt) { + //Using currentTarget instead of target for Firefox 2.0's sake. Not + //all old browsers will be supported, but this one was easy enough + //to support and still makes sense. + if (evt.type === 'load' || + (readyRegExp.test((evt.currentTarget || evt.srcElement).readyState))) { + //Reset interactive script so a script node is not held onto for + //to long. + interactiveScript = null; + + //Pull out the name of the module and the context. + var data = getScriptData(evt); + context.completeLoad(data.id); + } + }, + + /** + * Callback for script errors. + */ + onScriptError: function (evt) { + var data = getScriptData(evt); + if (!hasPathFallback(data.id)) { + return onError(makeError('scripterror', 'Script error', evt, [data.id])); + } + } + }); + } + + /** + * Main entry point. + * + * If the only argument to require is a string, then the module that + * is represented by that string is fetched for the appropriate context. + * + * If the first argument is an array, then it will be treated as an array + * of dependency string names to fetch. An optional function callback can + * be specified to execute when all of those dependencies are available. + * + * Make a local req variable to help Caja compliance (it assumes things + * on a require that are not standardized), and to give a short + * name for minification/local scope use. + */ + req = requirejs = function (deps, callback, errback, optional) { + + //Find the right context, use default + var context, config, + contextName = defContextName; + + // Determine if have config object in the call. + if (!isArray(deps) && typeof deps !== 'string') { + // deps is a config object + config = deps; + if (isArray(callback)) { + // Adjust args if there are dependencies + deps = callback; + callback = errback; + errback = optional; + } else { + deps = []; + } + } + + if (config && config.context) { + contextName = config.context; + } + + context = contexts[contextName]; + if (!context) { + context = contexts[contextName] = req.s.newContext(contextName); + } + + if (config) { + context.configure(config); + } + + return context.require(deps, callback, errback); + }; + + /** + * Support require.config() to make it easier to cooperate with other + * AMD loaders on globally agreed names. + */ + req.config = function (config) { + return req(config); + }; + + /** + * Export require as a global, but only if it does not already exist. + */ + if (!require) { + require = req; + } + + req.version = version; + + //Used to filter out dependencies that are already paths. + req.jsExtRegExp = /^\/|:|\?|\.js$/; + req.isBrowser = isBrowser; + s = req.s = { + contexts: contexts, + newContext: newContext + }; + + //Create default context. + req({}); + + //Exports some context-sensitive methods on global require, using + //default context if no context specified. + addRequireMethods(req); + + if (isBrowser) { + head = s.head = document.getElementsByTagName('head')[0]; + //If BASE tag is in play, using appendChild is a problem for IE6. + //When that browser dies, this can be removed. Details in this jQuery bug: + //http://dev.jquery.com/ticket/2709 + baseElement = document.getElementsByTagName('base')[0]; + if (baseElement) { + head = s.head = baseElement.parentNode; + } + } + + /** + * Any errors that require explicitly generates will be passed to this + * function. Intercept/override it if you want custom error handling. + * @param {Error} err the error object. + */ + req.onError = function (err) { + throw err; + }; + + /** + * Does the request to load a module for the browser case. + * Make this a separate function to allow other environments + * to override it. + * + * @param {Object} context the require context to find state. + * @param {String} moduleName the name of the module. + * @param {Object} url the URL to the module. + */ + req.load = function (context, moduleName, url) { + var config = (context && context.config) || {}, + node; + if (isBrowser) { + //In the browser so use a script tag + node = config.xhtml ? + document.createElementNS('http://www.w3.org/1999/xhtml', 'html:script') : + document.createElement('script'); + node.type = config.scriptType || 'text/javascript'; + node.charset = 'utf-8'; + node.async = true; + + node.setAttribute('data-requirecontext', context.contextName); + node.setAttribute('data-requiremodule', moduleName); + + //Set up load listener. Test attachEvent first because IE9 has + //a subtle issue in its addEventListener and script onload firings + //that do not match the behavior of all other browsers with + //addEventListener support, which fire the onload event for a + //script right after the script execution. See: + //https://connect.microsoft.com/IE/feedback/details/648057/script-onload-event-is-not-fired-immediately-after-script-execution + //UNFORTUNATELY Opera implements attachEvent but does not follow the script + //script execution mode. + if (node.attachEvent && + //Check if node.attachEvent is artificially added by custom script or + //natively supported by browser + //read https://github.com/jrburke/requirejs/issues/187 + //if we can NOT find [native code] then it must NOT natively supported. + //in IE8, node.attachEvent does not have toString() + //Note the test for "[native code" with no closing brace, see: + //https://github.com/jrburke/requirejs/issues/273 + !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && + !isOpera) { + //Probably IE. IE (at least 6-8) do not fire + //script onload right after executing the script, so + //we cannot tie the anonymous define call to a name. + //However, IE reports the script as being in 'interactive' + //readyState at the time of the define call. + useInteractive = true; + + node.attachEvent('onreadystatechange', context.onScriptLoad); + //It would be great to add an error handler here to catch + //404s in IE9+. However, onreadystatechange will fire before + //the error handler, so that does not help. If addEvenListener + //is used, then IE will fire error before load, but we cannot + //use that pathway given the connect.microsoft.com issue + //mentioned above about not doing the 'script execute, + //then fire the script load event listener before execute + //next script' that other browsers do. + //Best hope: IE10 fixes the issues, + //and then destroys all installs of IE 6-9. + //node.attachEvent('onerror', context.onScriptError); + } else { + node.addEventListener('load', context.onScriptLoad, false); + node.addEventListener('error', context.onScriptError, false); + } + node.src = url; + + //For some cache cases in IE 6-8, the script executes before the end + //of the appendChild execution, so to tie an anonymous define + //call to the module name (which is stored on the node), hold on + //to a reference to this node, but clear after the DOM insertion. + currentlyAddingScript = node; + if (baseElement) { + head.insertBefore(node, baseElement); + } else { + head.appendChild(node); + } + currentlyAddingScript = null; + + return node; + } else if (isWebWorker) { + //In a web worker, use importScripts. This is not a very + //efficient use of importScripts, importScripts will block until + //its script is downloaded and evaluated. However, if web workers + //are in play, the expectation that a build has been done so that + //only one script needs to be loaded anyway. This may need to be + //reevaluated if other use cases become common. + importScripts(url); + + //Account for anonymous modules + context.completeLoad(moduleName); + } + }; + + function getInteractiveScript() { + if (interactiveScript && interactiveScript.readyState === 'interactive') { + return interactiveScript; + } + + eachReverse(scripts(), function (script) { + if (script.readyState === 'interactive') { + return (interactiveScript = script); + } + }); + return interactiveScript; + } + + //Look for a data-main script attribute, which could also adjust the baseUrl. + if (isBrowser) { + //Figure out baseUrl. Get it from the script tag with require.js in it. + eachReverse(scripts(), function (script) { + //Set the 'head' where we can append children by + //using the script's parent. + if (!head) { + head = script.parentNode; + } + + //Look for a data-main attribute to set main script for the page + //to load. If it is there, the path to data main becomes the + //baseUrl, if it is not already set. + dataMain = script.getAttribute('data-main'); + if (dataMain) { + //Set final baseUrl if there is not already an explicit one. + if (!cfg.baseUrl) { + //Pull off the directory of data-main for use as the + //baseUrl. + src = dataMain.split('/'); + mainScript = src.pop(); + subPath = src.length ? src.join('/') + '/' : './'; + + cfg.baseUrl = subPath; + dataMain = mainScript; + } + + //Strip off any trailing .js since dataMain is now + //like a module name. + dataMain = dataMain.replace(jsSuffixRegExp, ''); + + //Put the data-main script in the files to load. + cfg.deps = cfg.deps ? cfg.deps.concat(dataMain) : [dataMain]; + + return true; + } + }); + } + + /** + * The function that handles definitions of modules. Differs from + * require() in that a string for the module should be the first argument, + * and the function to execute after dependencies are loaded should + * return a value to define the module corresponding to the first argument's + * name. + */ + define = function (name, deps, callback) { + var node, context; + + //Allow for anonymous functions + if (typeof name !== 'string') { + //Adjust args appropriately + callback = deps; + deps = name; + name = null; + } + + //This module may not have dependencies + if (!isArray(deps)) { + callback = deps; + deps = []; + } + + //If no name, and callback is a function, then figure out if it a + //CommonJS thing with dependencies. + if (!deps.length && isFunction(callback)) { + //Remove comments from the callback string, + //look for require calls, and pull them into the dependencies, + //but only if there are function args. + if (callback.length) { + callback + .toString() + .replace(commentRegExp, '') + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + + //May be a CommonJS thing even without require calls, but still + //could use exports, and module. Avoid doing exports and module + //work though if it just needs require. + //REQUIRES the function to expect the CommonJS variables in the + //order listed below. + deps = (callback.length === 1 ? ['require'] : ['require', 'exports', 'module']).concat(deps); + } + } + + //If in IE 6-8 and hit an anonymous define() call, do the interactive + //work. + if (useInteractive) { + node = currentlyAddingScript || getInteractiveScript(); + if (node) { + if (!name) { + name = node.getAttribute('data-requiremodule'); + } + context = contexts[node.getAttribute('data-requirecontext')]; + } + } + + //Always save off evaluating the def call until the script onload handler. + //This allows multiple modules to be in a file without prematurely + //tracing dependencies, and allows for anonymous module support, + //where the module name is not known until the script onload event + //occurs. If no context, use the global queue, and get it processed + //in the onscript load callback. + (context ? context.defQueue : globalDefQueue).push([name, deps, callback]); + }; + + define.amd = { + jQuery: true + }; + + + /** + * Executes the text. Normally just uses eval, but can be modified + * to use a better, environment-specific call. Only used for transpiling + * loader plugins, not for plain JS modules. + * @param {String} text the text to execute/evaluate. + */ + req.exec = function (text) { + /*jslint evil: true */ + return eval(text); + }; + + //Set up with config info. + req(cfg); +}(this)); |