Home | History | Annotate | Download | only in src
      1 /**
      2  * Sinon.JS 1.10.0, 2014/05/19
      3  *
      4  * @author Christian Johansen (christian (at) cjohansen.no)
      5  * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
      6  *
      7  * (The BSD License)
      8  *
      9  * Copyright (c) 2010-2014, Christian Johansen, christian (at) cjohansen.no
     10  * All rights reserved.
     11  *
     12  * Redistribution and use in source and binary forms, with or without modification,
     13  * are permitted provided that the following conditions are met:
     14  *
     15  *     * Redistributions of source code must retain the above copyright notice,
     16  *       this list of conditions and the following disclaimer.
     17  *     * Redistributions in binary form must reproduce the above copyright notice,
     18  *       this list of conditions and the following disclaimer in the documentation
     19  *       and/or other materials provided with the distribution.
     20  *     * Neither the name of Christian Johansen nor the names of his contributors
     21  *       may be used to endorse or promote products derived from this software
     22  *       without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     27  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34  */
     35 
     36 this.sinon = (function () {
     37 var samsam, formatio;
     38 function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } }
     39 define.amd = {};
     40 ((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
     41  (typeof module === "object" &&
     42       function (m) { module.exports = m(); }) || // Node
     43  function (m) { this.samsam = m(); } // Browser globals
     44 )(function () {
     45     var o = Object.prototype;
     46     var div = typeof document !== "undefined" && document.createElement("div");
     47 
     48     function isNaN(value) {
     49         // Unlike global isNaN, this avoids type coercion
     50         // typeof check avoids IE host object issues, hat tip to
     51         // lodash
     52         var val = value; // JsLint thinks value !== value is "weird"
     53         return typeof value === "number" && value !== val;
     54     }
     55 
     56     function getClass(value) {
     57         // Returns the internal [[Class]] by calling Object.prototype.toString
     58         // with the provided value as this. Return value is a string, naming the
     59         // internal class, e.g. "Array"
     60         return o.toString.call(value).split(/[ \]]/)[1];
     61     }
     62 
     63     /**
     64      * @name samsam.isArguments
     65      * @param Object object
     66      *
     67      * Returns ``true`` if ``object`` is an ``arguments`` object,
     68      * ``false`` otherwise.
     69      */
     70     function isArguments(object) {
     71         if (typeof object !== "object" || typeof object.length !== "number" ||
     72                 getClass(object) === "Array") {
     73             return false;
     74         }
     75         if (typeof object.callee == "function") { return true; }
     76         try {
     77             object[object.length] = 6;
     78             delete object[object.length];
     79         } catch (e) {
     80             return true;
     81         }
     82         return false;
     83     }
     84 
     85     /**
     86      * @name samsam.isElement
     87      * @param Object object
     88      *
     89      * Returns ``true`` if ``object`` is a DOM element node. Unlike
     90      * Underscore.js/lodash, this function will return ``false`` if ``object``
     91      * is an *element-like* object, i.e. a regular object with a ``nodeType``
     92      * property that holds the value ``1``.
     93      */
     94     function isElement(object) {
     95         if (!object || object.nodeType !== 1 || !div) { return false; }
     96         try {
     97             object.appendChild(div);
     98             object.removeChild(div);
     99         } catch (e) {
    100             return false;
    101         }
    102         return true;
    103     }
    104 
    105     /**
    106      * @name samsam.keys
    107      * @param Object object
    108      *
    109      * Return an array of own property names.
    110      */
    111     function keys(object) {
    112         var ks = [], prop;
    113         for (prop in object) {
    114             if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
    115         }
    116         return ks;
    117     }
    118 
    119     /**
    120      * @name samsam.isDate
    121      * @param Object value
    122      *
    123      * Returns true if the object is a ``Date``, or *date-like*. Duck typing
    124      * of date objects work by checking that the object has a ``getTime``
    125      * function whose return value equals the return value from the object's
    126      * ``valueOf``.
    127      */
    128     function isDate(value) {
    129         return typeof value.getTime == "function" &&
    130             value.getTime() == value.valueOf();
    131     }
    132 
    133     /**
    134      * @name samsam.isNegZero
    135      * @param Object value
    136      *
    137      * Returns ``true`` if ``value`` is ``-0``.
    138      */
    139     function isNegZero(value) {
    140         return value === 0 && 1 / value === -Infinity;
    141     }
    142 
    143     /**
    144      * @name samsam.equal
    145      * @param Object obj1
    146      * @param Object obj2
    147      *
    148      * Returns ``true`` if two objects are strictly equal. Compared to
    149      * ``===`` there are two exceptions:
    150      *
    151      *   - NaN is considered equal to NaN
    152      *   - -0 and +0 are not considered equal
    153      */
    154     function identical(obj1, obj2) {
    155         if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
    156             return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
    157         }
    158     }
    159 
    160 
    161     /**
    162      * @name samsam.deepEqual
    163      * @param Object obj1
    164      * @param Object obj2
    165      *
    166      * Deep equal comparison. Two values are "deep equal" if:
    167      *
    168      *   - They are equal, according to samsam.identical
    169      *   - They are both date objects representing the same time
    170      *   - They are both arrays containing elements that are all deepEqual
    171      *   - They are objects with the same set of properties, and each property
    172      *     in ``obj1`` is deepEqual to the corresponding property in ``obj2``
    173      *
    174      * Supports cyclic objects.
    175      */
    176     function deepEqualCyclic(obj1, obj2) {
    177 
    178         // used for cyclic comparison
    179         // contain already visited objects
    180         var objects1 = [],
    181             objects2 = [],
    182         // contain pathes (position in the object structure)
    183         // of the already visited objects
    184         // indexes same as in objects arrays
    185             paths1 = [],
    186             paths2 = [],
    187         // contains combinations of already compared objects
    188         // in the manner: { "$1['ref']$2['ref']": true }
    189             compared = {};
    190 
    191         /**
    192          * used to check, if the value of a property is an object
    193          * (cyclic logic is only needed for objects)
    194          * only needed for cyclic logic
    195          */
    196         function isObject(value) {
    197 
    198             if (typeof value === 'object' && value !== null &&
    199                     !(value instanceof Boolean) &&
    200                     !(value instanceof Date)    &&
    201                     !(value instanceof Number)  &&
    202                     !(value instanceof RegExp)  &&
    203                     !(value instanceof String)) {
    204 
    205                 return true;
    206             }
    207 
    208             return false;
    209         }
    210 
    211         /**
    212          * returns the index of the given object in the
    213          * given objects array, -1 if not contained
    214          * only needed for cyclic logic
    215          */
    216         function getIndex(objects, obj) {
    217 
    218             var i;
    219             for (i = 0; i < objects.length; i++) {
    220                 if (objects[i] === obj) {
    221                     return i;
    222                 }
    223             }
    224 
    225             return -1;
    226         }
    227 
    228         // does the recursion for the deep equal check
    229         return (function deepEqual(obj1, obj2, path1, path2) {
    230             var type1 = typeof obj1;
    231             var type2 = typeof obj2;
    232 
    233             // == null also matches undefined
    234             if (obj1 === obj2 ||
    235                     isNaN(obj1) || isNaN(obj2) ||
    236                     obj1 == null || obj2 == null ||
    237                     type1 !== "object" || type2 !== "object") {
    238 
    239                 return identical(obj1, obj2);
    240             }
    241 
    242             // Elements are only equal if identical(expected, actual)
    243             if (isElement(obj1) || isElement(obj2)) { return false; }
    244 
    245             var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
    246             if (isDate1 || isDate2) {
    247                 if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
    248                     return false;
    249                 }
    250             }
    251 
    252             if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
    253                 if (obj1.toString() !== obj2.toString()) { return false; }
    254             }
    255 
    256             var class1 = getClass(obj1);
    257             var class2 = getClass(obj2);
    258             var keys1 = keys(obj1);
    259             var keys2 = keys(obj2);
    260 
    261             if (isArguments(obj1) || isArguments(obj2)) {
    262                 if (obj1.length !== obj2.length) { return false; }
    263             } else {
    264                 if (type1 !== type2 || class1 !== class2 ||
    265                         keys1.length !== keys2.length) {
    266                     return false;
    267                 }
    268             }
    269 
    270             var key, i, l,
    271                 // following vars are used for the cyclic logic
    272                 value1, value2,
    273                 isObject1, isObject2,
    274                 index1, index2,
    275                 newPath1, newPath2;
    276 
    277             for (i = 0, l = keys1.length; i < l; i++) {
    278                 key = keys1[i];
    279                 if (!o.hasOwnProperty.call(obj2, key)) {
    280                     return false;
    281                 }
    282 
    283                 // Start of the cyclic logic
    284 
    285                 value1 = obj1[key];
    286                 value2 = obj2[key];
    287 
    288                 isObject1 = isObject(value1);
    289                 isObject2 = isObject(value2);
    290 
    291                 // determine, if the objects were already visited
    292                 // (it's faster to check for isObject first, than to
    293                 // get -1 from getIndex for non objects)
    294                 index1 = isObject1 ? getIndex(objects1, value1) : -1;
    295                 index2 = isObject2 ? getIndex(objects2, value2) : -1;
    296 
    297                 // determine the new pathes of the objects
    298                 // - for non cyclic objects the current path will be extended
    299                 //   by current property name
    300                 // - for cyclic objects the stored path is taken
    301                 newPath1 = index1 !== -1
    302                     ? paths1[index1]
    303                     : path1 + '[' + JSON.stringify(key) + ']';
    304                 newPath2 = index2 !== -1
    305                     ? paths2[index2]
    306                     : path2 + '[' + JSON.stringify(key) + ']';
    307 
    308                 // stop recursion if current objects are already compared
    309                 if (compared[newPath1 + newPath2]) {
    310                     return true;
    311                 }
    312 
    313                 // remember the current objects and their pathes
    314                 if (index1 === -1 && isObject1) {
    315                     objects1.push(value1);
    316                     paths1.push(newPath1);
    317                 }
    318                 if (index2 === -1 && isObject2) {
    319                     objects2.push(value2);
    320                     paths2.push(newPath2);
    321                 }
    322 
    323                 // remember that the current objects are already compared
    324                 if (isObject1 && isObject2) {
    325                     compared[newPath1 + newPath2] = true;
    326                 }
    327 
    328                 // End of cyclic logic
    329 
    330                 // neither value1 nor value2 is a cycle
    331                 // continue with next level
    332                 if (!deepEqual(value1, value2, newPath1, newPath2)) {
    333                     return false;
    334                 }
    335             }
    336 
    337             return true;
    338 
    339         }(obj1, obj2, '$1', '$2'));
    340     }
    341 
    342     var match;
    343 
    344     function arrayContains(array, subset) {
    345         if (subset.length === 0) { return true; }
    346         var i, l, j, k;
    347         for (i = 0, l = array.length; i < l; ++i) {
    348             if (match(array[i], subset[0])) {
    349                 for (j = 0, k = subset.length; j < k; ++j) {
    350                     if (!match(array[i + j], subset[j])) { return false; }
    351                 }
    352                 return true;
    353             }
    354         }
    355         return false;
    356     }
    357 
    358     /**
    359      * @name samsam.match
    360      * @param Object object
    361      * @param Object matcher
    362      *
    363      * Compare arbitrary value ``object`` with matcher.
    364      */
    365     match = function match(object, matcher) {
    366         if (matcher && typeof matcher.test === "function") {
    367             return matcher.test(object);
    368         }
    369 
    370         if (typeof matcher === "function") {
    371             return matcher(object) === true;
    372         }
    373 
    374         if (typeof matcher === "string") {
    375             matcher = matcher.toLowerCase();
    376             var notNull = typeof object === "string" || !!object;
    377             return notNull &&
    378                 (String(object)).toLowerCase().indexOf(matcher) >= 0;
    379         }
    380 
    381         if (typeof matcher === "number") {
    382             return matcher === object;
    383         }
    384 
    385         if (typeof matcher === "boolean") {
    386             return matcher === object;
    387         }
    388 
    389         if (getClass(object) === "Array" && getClass(matcher) === "Array") {
    390             return arrayContains(object, matcher);
    391         }
    392 
    393         if (matcher && typeof matcher === "object") {
    394             var prop;
    395             for (prop in matcher) {
    396                 if (!match(object[prop], matcher[prop])) {
    397                     return false;
    398                 }
    399             }
    400             return true;
    401         }
    402 
    403         throw new Error("Matcher was not a string, a number, a " +
    404                         "function, a boolean or an object");
    405     };
    406 
    407     return {
    408         isArguments: isArguments,
    409         isElement: isElement,
    410         isDate: isDate,
    411         isNegZero: isNegZero,
    412         identical: identical,
    413         deepEqual: deepEqualCyclic,
    414         match: match,
    415         keys: keys
    416     };
    417 });
    418 ((typeof define === "function" && define.amd && function (m) {
    419     define("formatio", ["samsam"], m);
    420 }) || (typeof module === "object" && function (m) {
    421     module.exports = m(require("samsam"));
    422 }) || function (m) { this.formatio = m(this.samsam); }
    423 )(function (samsam) {
    424 
    425     var formatio = {
    426         excludeConstructors: ["Object", /^.$/],
    427         quoteStrings: true
    428     };
    429 
    430     var hasOwn = Object.prototype.hasOwnProperty;
    431 
    432     var specialObjects = [];
    433     if (typeof global !== "undefined") {
    434         specialObjects.push({ object: global, value: "[object global]" });
    435     }
    436     if (typeof document !== "undefined") {
    437         specialObjects.push({
    438             object: document,
    439             value: "[object HTMLDocument]"
    440         });
    441     }
    442     if (typeof window !== "undefined") {
    443         specialObjects.push({ object: window, value: "[object Window]" });
    444     }
    445 
    446     function functionName(func) {
    447         if (!func) { return ""; }
    448         if (func.displayName) { return func.displayName; }
    449         if (func.name) { return func.name; }
    450         var matches = func.toString().match(/function\s+([^\(]+)/m);
    451         return (matches && matches[1]) || "";
    452     }
    453 
    454     function constructorName(f, object) {
    455         var name = functionName(object && object.constructor);
    456         var excludes = f.excludeConstructors ||
    457                 formatio.excludeConstructors || [];
    458 
    459         var i, l;
    460         for (i = 0, l = excludes.length; i < l; ++i) {
    461             if (typeof excludes[i] === "string" && excludes[i] === name) {
    462                 return "";
    463             } else if (excludes[i].test && excludes[i].test(name)) {
    464                 return "";
    465             }
    466         }
    467 
    468         return name;
    469     }
    470 
    471     function isCircular(object, objects) {
    472         if (typeof object !== "object") { return false; }
    473         var i, l;
    474         for (i = 0, l = objects.length; i < l; ++i) {
    475             if (objects[i] === object) { return true; }
    476         }
    477         return false;
    478     }
    479 
    480     function ascii(f, object, processed, indent) {
    481         if (typeof object === "string") {
    482             var qs = f.quoteStrings;
    483             var quote = typeof qs !== "boolean" || qs;
    484             return processed || quote ? '"' + object + '"' : object;
    485         }
    486 
    487         if (typeof object === "function" && !(object instanceof RegExp)) {
    488             return ascii.func(object);
    489         }
    490 
    491         processed = processed || [];
    492 
    493         if (isCircular(object, processed)) { return "[Circular]"; }
    494 
    495         if (Object.prototype.toString.call(object) === "[object Array]") {
    496             return ascii.array.call(f, object, processed);
    497         }
    498 
    499         if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
    500         if (samsam.isElement(object)) { return ascii.element(object); }
    501 
    502         if (typeof object.toString === "function" &&
    503                 object.toString !== Object.prototype.toString) {
    504             return object.toString();
    505         }
    506 
    507         var i, l;
    508         for (i = 0, l = specialObjects.length; i < l; i++) {
    509             if (object === specialObjects[i].object) {
    510                 return specialObjects[i].value;
    511             }
    512         }
    513 
    514         return ascii.object.call(f, object, processed, indent);
    515     }
    516 
    517     ascii.func = function (func) {
    518         return "function " + functionName(func) + "() {}";
    519     };
    520 
    521     ascii.array = function (array, processed) {
    522         processed = processed || [];
    523         processed.push(array);
    524         var i, l, pieces = [];
    525         for (i = 0, l = array.length; i < l; ++i) {
    526             pieces.push(ascii(this, array[i], processed));
    527         }
    528         return "[" + pieces.join(", ") + "]";
    529     };
    530 
    531     ascii.object = function (object, processed, indent) {
    532         processed = processed || [];
    533         processed.push(object);
    534         indent = indent || 0;
    535         var pieces = [], properties = samsam.keys(object).sort();
    536         var length = 3;
    537         var prop, str, obj, i, l;
    538 
    539         for (i = 0, l = properties.length; i < l; ++i) {
    540             prop = properties[i];
    541             obj = object[prop];
    542 
    543             if (isCircular(obj, processed)) {
    544                 str = "[Circular]";
    545             } else {
    546                 str = ascii(this, obj, processed, indent + 2);
    547             }
    548 
    549             str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
    550             length += str.length;
    551             pieces.push(str);
    552         }
    553 
    554         var cons = constructorName(this, object);
    555         var prefix = cons ? "[" + cons + "] " : "";
    556         var is = "";
    557         for (i = 0, l = indent; i < l; ++i) { is += " "; }
    558 
    559         if (length + indent > 80) {
    560             return prefix + "{\n  " + is + pieces.join(",\n  " + is) + "\n" +
    561                 is + "}";
    562         }
    563         return prefix + "{ " + pieces.join(", ") + " }";
    564     };
    565 
    566     ascii.element = function (element) {
    567         var tagName = element.tagName.toLowerCase();
    568         var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
    569 
    570         for (i = 0, l = attrs.length; i < l; ++i) {
    571             attr = attrs.item(i);
    572             attrName = attr.nodeName.toLowerCase().replace("html:", "");
    573             val = attr.nodeValue;
    574             if (attrName !== "contenteditable" || val !== "inherit") {
    575                 if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
    576             }
    577         }
    578 
    579         var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
    580         var content = element.innerHTML;
    581 
    582         if (content.length > 20) {
    583             content = content.substr(0, 20) + "[...]";
    584         }
    585 
    586         var res = formatted + pairs.join(" ") + ">" + content +
    587                 "</" + tagName + ">";
    588 
    589         return res.replace(/ contentEditable="inherit"/, "");
    590     };
    591 
    592     function Formatio(options) {
    593         for (var opt in options) {
    594             this[opt] = options[opt];
    595         }
    596     }
    597 
    598     Formatio.prototype = {
    599         functionName: functionName,
    600 
    601         configure: function (options) {
    602             return new Formatio(options);
    603         },
    604 
    605         constructorName: function (object) {
    606             return constructorName(this, object);
    607         },
    608 
    609         ascii: function (object, processed, indent) {
    610             return ascii(this, object, processed, indent);
    611         }
    612     };
    613 
    614     return Formatio.prototype;
    615 });
    616 /*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
    617 /*global module, require, __dirname, document*/
    618 /**
    619  * Sinon core utilities. For internal use only.
    620  *
    621  * @author Christian Johansen (christian (at) cjohansen.no)
    622  * @license BSD
    623  *
    624  * Copyright (c) 2010-2013 Christian Johansen
    625  */
    626 
    627 var sinon = (function (formatio) {
    628     var div = typeof document != "undefined" && document.createElement("div");
    629     var hasOwn = Object.prototype.hasOwnProperty;
    630 
    631     function isDOMNode(obj) {
    632         var success = false;
    633 
    634         try {
    635             obj.appendChild(div);
    636             success = div.parentNode == obj;
    637         } catch (e) {
    638             return false;
    639         } finally {
    640             try {
    641                 obj.removeChild(div);
    642             } catch (e) {
    643                 // Remove failed, not much we can do about that
    644             }
    645         }
    646 
    647         return success;
    648     }
    649 
    650     function isElement(obj) {
    651         return div && obj && obj.nodeType === 1 && isDOMNode(obj);
    652     }
    653 
    654     function isFunction(obj) {
    655         return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
    656     }
    657 
    658     function isReallyNaN(val) {
    659         return typeof val === 'number' && isNaN(val);
    660     }
    661 
    662     function mirrorProperties(target, source) {
    663         for (var prop in source) {
    664             if (!hasOwn.call(target, prop)) {
    665                 target[prop] = source[prop];
    666             }
    667         }
    668     }
    669 
    670     function isRestorable (obj) {
    671         return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
    672     }
    673 
    674     var sinon = {
    675         wrapMethod: function wrapMethod(object, property, method) {
    676             if (!object) {
    677                 throw new TypeError("Should wrap property of object");
    678             }
    679 
    680             if (typeof method != "function") {
    681                 throw new TypeError("Method wrapper should be function");
    682             }
    683 
    684             var wrappedMethod = object[property],
    685                 error;
    686 
    687             if (!isFunction(wrappedMethod)) {
    688                 error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
    689                                     property + " as function");
    690             } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
    691                 error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
    692             } else if (wrappedMethod.calledBefore) {
    693                 var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
    694                 error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
    695             }
    696 
    697             if (error) {
    698                 if (wrappedMethod && wrappedMethod._stack) {
    699                     error.stack += '\n--------------\n' + wrappedMethod._stack;
    700                 }
    701                 throw error;
    702             }
    703 
    704             // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
    705             // when using hasOwn.call on objects from other frames.
    706             var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
    707             object[property] = method;
    708             method.displayName = property;
    709             // Set up a stack trace which can be used later to find what line of
    710             // code the original method was created on.
    711             method._stack = (new Error('Stack Trace for original')).stack;
    712 
    713             method.restore = function () {
    714                 // For prototype properties try to reset by delete first.
    715                 // If this fails (ex: localStorage on mobile safari) then force a reset
    716                 // via direct assignment.
    717                 if (!owned) {
    718                     delete object[property];
    719                 }
    720                 if (object[property] === method) {
    721                     object[property] = wrappedMethod;
    722                 }
    723             };
    724 
    725             method.restore.sinon = true;
    726             mirrorProperties(method, wrappedMethod);
    727 
    728             return method;
    729         },
    730 
    731         extend: function extend(target) {
    732             for (var i = 1, l = arguments.length; i < l; i += 1) {
    733                 for (var prop in arguments[i]) {
    734                     if (arguments[i].hasOwnProperty(prop)) {
    735                         target[prop] = arguments[i][prop];
    736                     }
    737 
    738                     // DONT ENUM bug, only care about toString
    739                     if (arguments[i].hasOwnProperty("toString") &&
    740                         arguments[i].toString != target.toString) {
    741                         target.toString = arguments[i].toString;
    742                     }
    743                 }
    744             }
    745 
    746             return target;
    747         },
    748 
    749         create: function create(proto) {
    750             var F = function () {};
    751             F.prototype = proto;
    752             return new F();
    753         },
    754 
    755         deepEqual: function deepEqual(a, b) {
    756             if (sinon.match && sinon.match.isMatcher(a)) {
    757                 return a.test(b);
    758             }
    759 
    760             if (typeof a != 'object' || typeof b != 'object') {
    761                 if (isReallyNaN(a) && isReallyNaN(b)) {
    762                     return true;
    763                 } else {
    764                     return a === b;
    765                 }
    766             }
    767 
    768             if (isElement(a) || isElement(b)) {
    769                 return a === b;
    770             }
    771 
    772             if (a === b) {
    773                 return true;
    774             }
    775 
    776             if ((a === null && b !== null) || (a !== null && b === null)) {
    777                 return false;
    778             }
    779 
    780             if (a instanceof RegExp && b instanceof RegExp) {
    781               return (a.source === b.source) && (a.global === b.global) &&
    782                 (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
    783             }
    784 
    785             var aString = Object.prototype.toString.call(a);
    786             if (aString != Object.prototype.toString.call(b)) {
    787                 return false;
    788             }
    789 
    790             if (aString == "[object Date]") {
    791                 return a.valueOf() === b.valueOf();
    792             }
    793 
    794             var prop, aLength = 0, bLength = 0;
    795 
    796             if (aString == "[object Array]" && a.length !== b.length) {
    797                 return false;
    798             }
    799 
    800             for (prop in a) {
    801                 aLength += 1;
    802 
    803                 if (!(prop in b)) {
    804                     return false;
    805                 }
    806 
    807                 if (!deepEqual(a[prop], b[prop])) {
    808                     return false;
    809                 }
    810             }
    811 
    812             for (prop in b) {
    813                 bLength += 1;
    814             }
    815 
    816             return aLength == bLength;
    817         },
    818 
    819         functionName: function functionName(func) {
    820             var name = func.displayName || func.name;
    821 
    822             // Use function decomposition as a last resort to get function
    823             // name. Does not rely on function decomposition to work - if it
    824             // doesn't debugging will be slightly less informative
    825             // (i.e. toString will say 'spy' rather than 'myFunc').
    826             if (!name) {
    827                 var matches = func.toString().match(/function ([^\s\(]+)/);
    828                 name = matches && matches[1];
    829             }
    830 
    831             return name;
    832         },
    833 
    834         functionToString: function toString() {
    835             if (this.getCall && this.callCount) {
    836                 var thisValue, prop, i = this.callCount;
    837 
    838                 while (i--) {
    839                     thisValue = this.getCall(i).thisValue;
    840 
    841                     for (prop in thisValue) {
    842                         if (thisValue[prop] === this) {
    843                             return prop;
    844                         }
    845                     }
    846                 }
    847             }
    848 
    849             return this.displayName || "sinon fake";
    850         },
    851 
    852         getConfig: function (custom) {
    853             var config = {};
    854             custom = custom || {};
    855             var defaults = sinon.defaultConfig;
    856 
    857             for (var prop in defaults) {
    858                 if (defaults.hasOwnProperty(prop)) {
    859                     config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
    860                 }
    861             }
    862 
    863             return config;
    864         },
    865 
    866         format: function (val) {
    867             return "" + val;
    868         },
    869 
    870         defaultConfig: {
    871             injectIntoThis: true,
    872             injectInto: null,
    873             properties: ["spy", "stub", "mock", "clock", "server", "requests"],
    874             useFakeTimers: true,
    875             useFakeServer: true
    876         },
    877 
    878         timesInWords: function timesInWords(count) {
    879             return count == 1 && "once" ||
    880                 count == 2 && "twice" ||
    881                 count == 3 && "thrice" ||
    882                 (count || 0) + " times";
    883         },
    884 
    885         calledInOrder: function (spies) {
    886             for (var i = 1, l = spies.length; i < l; i++) {
    887                 if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
    888                     return false;
    889                 }
    890             }
    891 
    892             return true;
    893         },
    894 
    895         orderByFirstCall: function (spies) {
    896             return spies.sort(function (a, b) {
    897                 // uuid, won't ever be equal
    898                 var aCall = a.getCall(0);
    899                 var bCall = b.getCall(0);
    900                 var aId = aCall && aCall.callId || -1;
    901                 var bId = bCall && bCall.callId || -1;
    902 
    903                 return aId < bId ? -1 : 1;
    904             });
    905         },
    906 
    907         log: function () {},
    908 
    909         logError: function (label, err) {
    910             var msg = label + " threw exception: ";
    911             sinon.log(msg + "[" + err.name + "] " + err.message);
    912             if (err.stack) { sinon.log(err.stack); }
    913 
    914             setTimeout(function () {
    915                 err.message = msg + err.message;
    916                 throw err;
    917             }, 0);
    918         },
    919 
    920         typeOf: function (value) {
    921             if (value === null) {
    922                 return "null";
    923             }
    924             else if (value === undefined) {
    925                 return "undefined";
    926             }
    927             var string = Object.prototype.toString.call(value);
    928             return string.substring(8, string.length - 1).toLowerCase();
    929         },
    930 
    931         createStubInstance: function (constructor) {
    932             if (typeof constructor !== "function") {
    933                 throw new TypeError("The constructor should be a function.");
    934             }
    935             return sinon.stub(sinon.create(constructor.prototype));
    936         },
    937 
    938         restore: function (object) {
    939             if (object !== null && typeof object === "object") {
    940                 for (var prop in object) {
    941                     if (isRestorable(object[prop])) {
    942                         object[prop].restore();
    943                     }
    944                 }
    945             }
    946             else if (isRestorable(object)) {
    947                 object.restore();
    948             }
    949         }
    950     };
    951 
    952     var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
    953     var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
    954 
    955     function makePublicAPI(require, exports, module) {
    956         module.exports = sinon;
    957         sinon.spy = require("./sinon/spy");
    958         sinon.spyCall = require("./sinon/call");
    959         sinon.behavior = require("./sinon/behavior");
    960         sinon.stub = require("./sinon/stub");
    961         sinon.mock = require("./sinon/mock");
    962         sinon.collection = require("./sinon/collection");
    963         sinon.assert = require("./sinon/assert");
    964         sinon.sandbox = require("./sinon/sandbox");
    965         sinon.test = require("./sinon/test");
    966         sinon.testCase = require("./sinon/test_case");
    967         sinon.match = require("./sinon/match");
    968     }
    969 
    970     if (isAMD) {
    971         define(makePublicAPI);
    972     } else if (isNode) {
    973         try {
    974             formatio = require("formatio");
    975         } catch (e) {}
    976         makePublicAPI(require, exports, module);
    977     }
    978 
    979     if (formatio) {
    980         var formatter = formatio.configure({ quoteStrings: false });
    981         sinon.format = function () {
    982             return formatter.ascii.apply(formatter, arguments);
    983         };
    984     } else if (isNode) {
    985         try {
    986             var util = require("util");
    987             sinon.format = function (value) {
    988                 return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
    989             };
    990         } catch (e) {
    991             /* Node, but no util module - would be very old, but better safe than
    992              sorry */
    993         }
    994     }
    995 
    996     return sinon;
    997 }(typeof formatio == "object" && formatio));
    998 
    999 /* @depend ../sinon.js */
   1000 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
   1001 /*global module, require, sinon*/
   1002 /**
   1003  * Match functions
   1004  *
   1005  * @author Maximilian Antoni (mail (at) maxantoni.de)
   1006  * @license BSD
   1007  *
   1008  * Copyright (c) 2012 Maximilian Antoni
   1009  */
   1010 
   1011 (function (sinon) {
   1012     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   1013 
   1014     if (!sinon && commonJSModule) {
   1015         sinon = require("../sinon");
   1016     }
   1017 
   1018     if (!sinon) {
   1019         return;
   1020     }
   1021 
   1022     function assertType(value, type, name) {
   1023         var actual = sinon.typeOf(value);
   1024         if (actual !== type) {
   1025             throw new TypeError("Expected type of " + name + " to be " +
   1026                 type + ", but was " + actual);
   1027         }
   1028     }
   1029 
   1030     var matcher = {
   1031         toString: function () {
   1032             return this.message;
   1033         }
   1034     };
   1035 
   1036     function isMatcher(object) {
   1037         return matcher.isPrototypeOf(object);
   1038     }
   1039 
   1040     function matchObject(expectation, actual) {
   1041         if (actual === null || actual === undefined) {
   1042             return false;
   1043         }
   1044         for (var key in expectation) {
   1045             if (expectation.hasOwnProperty(key)) {
   1046                 var exp = expectation[key];
   1047                 var act = actual[key];
   1048                 if (match.isMatcher(exp)) {
   1049                     if (!exp.test(act)) {
   1050                         return false;
   1051                     }
   1052                 } else if (sinon.typeOf(exp) === "object") {
   1053                     if (!matchObject(exp, act)) {
   1054                         return false;
   1055                     }
   1056                 } else if (!sinon.deepEqual(exp, act)) {
   1057                     return false;
   1058                 }
   1059             }
   1060         }
   1061         return true;
   1062     }
   1063 
   1064     matcher.or = function (m2) {
   1065         if (!arguments.length) {
   1066             throw new TypeError("Matcher expected");
   1067         } else if (!isMatcher(m2)) {
   1068             m2 = match(m2);
   1069         }
   1070         var m1 = this;
   1071         var or = sinon.create(matcher);
   1072         or.test = function (actual) {
   1073             return m1.test(actual) || m2.test(actual);
   1074         };
   1075         or.message = m1.message + ".or(" + m2.message + ")";
   1076         return or;
   1077     };
   1078 
   1079     matcher.and = function (m2) {
   1080         if (!arguments.length) {
   1081             throw new TypeError("Matcher expected");
   1082         } else if (!isMatcher(m2)) {
   1083             m2 = match(m2);
   1084         }
   1085         var m1 = this;
   1086         var and = sinon.create(matcher);
   1087         and.test = function (actual) {
   1088             return m1.test(actual) && m2.test(actual);
   1089         };
   1090         and.message = m1.message + ".and(" + m2.message + ")";
   1091         return and;
   1092     };
   1093 
   1094     var match = function (expectation, message) {
   1095         var m = sinon.create(matcher);
   1096         var type = sinon.typeOf(expectation);
   1097         switch (type) {
   1098         case "object":
   1099             if (typeof expectation.test === "function") {
   1100                 m.test = function (actual) {
   1101                     return expectation.test(actual) === true;
   1102                 };
   1103                 m.message = "match(" + sinon.functionName(expectation.test) + ")";
   1104                 return m;
   1105             }
   1106             var str = [];
   1107             for (var key in expectation) {
   1108                 if (expectation.hasOwnProperty(key)) {
   1109                     str.push(key + ": " + expectation[key]);
   1110                 }
   1111             }
   1112             m.test = function (actual) {
   1113                 return matchObject(expectation, actual);
   1114             };
   1115             m.message = "match(" + str.join(", ") + ")";
   1116             break;
   1117         case "number":
   1118             m.test = function (actual) {
   1119                 return expectation == actual;
   1120             };
   1121             break;
   1122         case "string":
   1123             m.test = function (actual) {
   1124                 if (typeof actual !== "string") {
   1125                     return false;
   1126                 }
   1127                 return actual.indexOf(expectation) !== -1;
   1128             };
   1129             m.message = "match(\"" + expectation + "\")";
   1130             break;
   1131         case "regexp":
   1132             m.test = function (actual) {
   1133                 if (typeof actual !== "string") {
   1134                     return false;
   1135                 }
   1136                 return expectation.test(actual);
   1137             };
   1138             break;
   1139         case "function":
   1140             m.test = expectation;
   1141             if (message) {
   1142                 m.message = message;
   1143             } else {
   1144                 m.message = "match(" + sinon.functionName(expectation) + ")";
   1145             }
   1146             break;
   1147         default:
   1148             m.test = function (actual) {
   1149               return sinon.deepEqual(expectation, actual);
   1150             };
   1151         }
   1152         if (!m.message) {
   1153             m.message = "match(" + expectation + ")";
   1154         }
   1155         return m;
   1156     };
   1157 
   1158     match.isMatcher = isMatcher;
   1159 
   1160     match.any = match(function () {
   1161         return true;
   1162     }, "any");
   1163 
   1164     match.defined = match(function (actual) {
   1165         return actual !== null && actual !== undefined;
   1166     }, "defined");
   1167 
   1168     match.truthy = match(function (actual) {
   1169         return !!actual;
   1170     }, "truthy");
   1171 
   1172     match.falsy = match(function (actual) {
   1173         return !actual;
   1174     }, "falsy");
   1175 
   1176     match.same = function (expectation) {
   1177         return match(function (actual) {
   1178             return expectation === actual;
   1179         }, "same(" + expectation + ")");
   1180     };
   1181 
   1182     match.typeOf = function (type) {
   1183         assertType(type, "string", "type");
   1184         return match(function (actual) {
   1185             return sinon.typeOf(actual) === type;
   1186         }, "typeOf(\"" + type + "\")");
   1187     };
   1188 
   1189     match.instanceOf = function (type) {
   1190         assertType(type, "function", "type");
   1191         return match(function (actual) {
   1192             return actual instanceof type;
   1193         }, "instanceOf(" + sinon.functionName(type) + ")");
   1194     };
   1195 
   1196     function createPropertyMatcher(propertyTest, messagePrefix) {
   1197         return function (property, value) {
   1198             assertType(property, "string", "property");
   1199             var onlyProperty = arguments.length === 1;
   1200             var message = messagePrefix + "(\"" + property + "\"";
   1201             if (!onlyProperty) {
   1202                 message += ", " + value;
   1203             }
   1204             message += ")";
   1205             return match(function (actual) {
   1206                 if (actual === undefined || actual === null ||
   1207                         !propertyTest(actual, property)) {
   1208                     return false;
   1209                 }
   1210                 return onlyProperty || sinon.deepEqual(value, actual[property]);
   1211             }, message);
   1212         };
   1213     }
   1214 
   1215     match.has = createPropertyMatcher(function (actual, property) {
   1216         if (typeof actual === "object") {
   1217             return property in actual;
   1218         }
   1219         return actual[property] !== undefined;
   1220     }, "has");
   1221 
   1222     match.hasOwn = createPropertyMatcher(function (actual, property) {
   1223         return actual.hasOwnProperty(property);
   1224     }, "hasOwn");
   1225 
   1226     match.bool = match.typeOf("boolean");
   1227     match.number = match.typeOf("number");
   1228     match.string = match.typeOf("string");
   1229     match.object = match.typeOf("object");
   1230     match.func = match.typeOf("function");
   1231     match.array = match.typeOf("array");
   1232     match.regexp = match.typeOf("regexp");
   1233     match.date = match.typeOf("date");
   1234 
   1235     sinon.match = match;
   1236 
   1237     if (typeof define === "function" && define.amd) {
   1238         define(["module"], function(module) { module.exports = match; });
   1239     } else if (commonJSModule) {
   1240         module.exports = match;
   1241     }
   1242 }(typeof sinon == "object" && sinon || null));
   1243 
   1244 /**
   1245   * @depend ../sinon.js
   1246   * @depend match.js
   1247   */
   1248 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
   1249 /*global module, require, sinon*/
   1250 /**
   1251   * Spy calls
   1252   *
   1253   * @author Christian Johansen (christian (at) cjohansen.no)
   1254   * @author Maximilian Antoni (mail (at) maxantoni.de)
   1255   * @license BSD
   1256   *
   1257   * Copyright (c) 2010-2013 Christian Johansen
   1258   * Copyright (c) 2013 Maximilian Antoni
   1259   */
   1260 
   1261 (function (sinon) {
   1262     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   1263     if (!sinon && commonJSModule) {
   1264         sinon = require("../sinon");
   1265     }
   1266 
   1267     if (!sinon) {
   1268         return;
   1269     }
   1270 
   1271     function throwYieldError(proxy, text, args) {
   1272         var msg = sinon.functionName(proxy) + text;
   1273         if (args.length) {
   1274             msg += " Received [" + slice.call(args).join(", ") + "]";
   1275         }
   1276         throw new Error(msg);
   1277     }
   1278 
   1279     var slice = Array.prototype.slice;
   1280 
   1281     var callProto = {
   1282         calledOn: function calledOn(thisValue) {
   1283             if (sinon.match && sinon.match.isMatcher(thisValue)) {
   1284                 return thisValue.test(this.thisValue);
   1285             }
   1286             return this.thisValue === thisValue;
   1287         },
   1288 
   1289         calledWith: function calledWith() {
   1290             for (var i = 0, l = arguments.length; i < l; i += 1) {
   1291                 if (!sinon.deepEqual(arguments[i], this.args[i])) {
   1292                     return false;
   1293                 }
   1294             }
   1295 
   1296             return true;
   1297         },
   1298 
   1299         calledWithMatch: function calledWithMatch() {
   1300             for (var i = 0, l = arguments.length; i < l; i += 1) {
   1301                 var actual = this.args[i];
   1302                 var expectation = arguments[i];
   1303                 if (!sinon.match || !sinon.match(expectation).test(actual)) {
   1304                     return false;
   1305                 }
   1306             }
   1307             return true;
   1308         },
   1309 
   1310         calledWithExactly: function calledWithExactly() {
   1311             return arguments.length == this.args.length &&
   1312                 this.calledWith.apply(this, arguments);
   1313         },
   1314 
   1315         notCalledWith: function notCalledWith() {
   1316             return !this.calledWith.apply(this, arguments);
   1317         },
   1318 
   1319         notCalledWithMatch: function notCalledWithMatch() {
   1320             return !this.calledWithMatch.apply(this, arguments);
   1321         },
   1322 
   1323         returned: function returned(value) {
   1324             return sinon.deepEqual(value, this.returnValue);
   1325         },
   1326 
   1327         threw: function threw(error) {
   1328             if (typeof error === "undefined" || !this.exception) {
   1329                 return !!this.exception;
   1330             }
   1331 
   1332             return this.exception === error || this.exception.name === error;
   1333         },
   1334 
   1335         calledWithNew: function calledWithNew() {
   1336             return this.proxy.prototype && this.thisValue instanceof this.proxy;
   1337         },
   1338 
   1339         calledBefore: function (other) {
   1340             return this.callId < other.callId;
   1341         },
   1342 
   1343         calledAfter: function (other) {
   1344             return this.callId > other.callId;
   1345         },
   1346 
   1347         callArg: function (pos) {
   1348             this.args[pos]();
   1349         },
   1350 
   1351         callArgOn: function (pos, thisValue) {
   1352             this.args[pos].apply(thisValue);
   1353         },
   1354 
   1355         callArgWith: function (pos) {
   1356             this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
   1357         },
   1358 
   1359         callArgOnWith: function (pos, thisValue) {
   1360             var args = slice.call(arguments, 2);
   1361             this.args[pos].apply(thisValue, args);
   1362         },
   1363 
   1364         "yield": function () {
   1365             this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
   1366         },
   1367 
   1368         yieldOn: function (thisValue) {
   1369             var args = this.args;
   1370             for (var i = 0, l = args.length; i < l; ++i) {
   1371                 if (typeof args[i] === "function") {
   1372                     args[i].apply(thisValue, slice.call(arguments, 1));
   1373                     return;
   1374                 }
   1375             }
   1376             throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
   1377         },
   1378 
   1379         yieldTo: function (prop) {
   1380             this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
   1381         },
   1382 
   1383         yieldToOn: function (prop, thisValue) {
   1384             var args = this.args;
   1385             for (var i = 0, l = args.length; i < l; ++i) {
   1386                 if (args[i] && typeof args[i][prop] === "function") {
   1387                     args[i][prop].apply(thisValue, slice.call(arguments, 2));
   1388                     return;
   1389                 }
   1390             }
   1391             throwYieldError(this.proxy, " cannot yield to '" + prop +
   1392                 "' since no callback was passed.", args);
   1393         },
   1394 
   1395         toString: function () {
   1396             var callStr = this.proxy.toString() + "(";
   1397             var args = [];
   1398 
   1399             for (var i = 0, l = this.args.length; i < l; ++i) {
   1400                 args.push(sinon.format(this.args[i]));
   1401             }
   1402 
   1403             callStr = callStr + args.join(", ") + ")";
   1404 
   1405             if (typeof this.returnValue != "undefined") {
   1406                 callStr += " => " + sinon.format(this.returnValue);
   1407             }
   1408 
   1409             if (this.exception) {
   1410                 callStr += " !" + this.exception.name;
   1411 
   1412                 if (this.exception.message) {
   1413                     callStr += "(" + this.exception.message + ")";
   1414                 }
   1415             }
   1416 
   1417             return callStr;
   1418         }
   1419     };
   1420 
   1421     callProto.invokeCallback = callProto.yield;
   1422 
   1423     function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
   1424         if (typeof id !== "number") {
   1425             throw new TypeError("Call id is not a number");
   1426         }
   1427         var proxyCall = sinon.create(callProto);
   1428         proxyCall.proxy = spy;
   1429         proxyCall.thisValue = thisValue;
   1430         proxyCall.args = args;
   1431         proxyCall.returnValue = returnValue;
   1432         proxyCall.exception = exception;
   1433         proxyCall.callId = id;
   1434 
   1435         return proxyCall;
   1436     }
   1437     createSpyCall.toString = callProto.toString; // used by mocks
   1438 
   1439     sinon.spyCall = createSpyCall;
   1440 
   1441     if (typeof define === "function" && define.amd) {
   1442         define(["module"], function(module) { module.exports = createSpyCall; });
   1443     } else if (commonJSModule) {
   1444         module.exports = createSpyCall;
   1445     }
   1446 }(typeof sinon == "object" && sinon || null));
   1447 
   1448 
   1449 /**
   1450   * @depend ../sinon.js
   1451   * @depend call.js
   1452   */
   1453 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
   1454 /*global module, require, sinon*/
   1455 /**
   1456   * Spy functions
   1457   *
   1458   * @author Christian Johansen (christian (at) cjohansen.no)
   1459   * @license BSD
   1460   *
   1461   * Copyright (c) 2010-2013 Christian Johansen
   1462   */
   1463 
   1464 (function (sinon) {
   1465     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   1466     var push = Array.prototype.push;
   1467     var slice = Array.prototype.slice;
   1468     var callId = 0;
   1469 
   1470     if (!sinon && commonJSModule) {
   1471         sinon = require("../sinon");
   1472     }
   1473 
   1474     if (!sinon) {
   1475         return;
   1476     }
   1477 
   1478     function spy(object, property) {
   1479         if (!property && typeof object == "function") {
   1480             return spy.create(object);
   1481         }
   1482 
   1483         if (!object && !property) {
   1484             return spy.create(function () { });
   1485         }
   1486 
   1487         var method = object[property];
   1488         return sinon.wrapMethod(object, property, spy.create(method));
   1489     }
   1490 
   1491     function matchingFake(fakes, args, strict) {
   1492         if (!fakes) {
   1493             return;
   1494         }
   1495 
   1496         for (var i = 0, l = fakes.length; i < l; i++) {
   1497             if (fakes[i].matches(args, strict)) {
   1498                 return fakes[i];
   1499             }
   1500         }
   1501     }
   1502 
   1503     function incrementCallCount() {
   1504         this.called = true;
   1505         this.callCount += 1;
   1506         this.notCalled = false;
   1507         this.calledOnce = this.callCount == 1;
   1508         this.calledTwice = this.callCount == 2;
   1509         this.calledThrice = this.callCount == 3;
   1510     }
   1511 
   1512     function createCallProperties() {
   1513         this.firstCall = this.getCall(0);
   1514         this.secondCall = this.getCall(1);
   1515         this.thirdCall = this.getCall(2);
   1516         this.lastCall = this.getCall(this.callCount - 1);
   1517     }
   1518 
   1519     var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
   1520     function createProxy(func) {
   1521         // Retain the function length:
   1522         var p;
   1523         if (func.length) {
   1524             eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
   1525                 ") { return p.invoke(func, this, slice.call(arguments)); });");
   1526         }
   1527         else {
   1528             p = function proxy() {
   1529                 return p.invoke(func, this, slice.call(arguments));
   1530             };
   1531         }
   1532         return p;
   1533     }
   1534 
   1535     var uuid = 0;
   1536 
   1537     // Public API
   1538     var spyApi = {
   1539         reset: function () {
   1540             this.called = false;
   1541             this.notCalled = true;
   1542             this.calledOnce = false;
   1543             this.calledTwice = false;
   1544             this.calledThrice = false;
   1545             this.callCount = 0;
   1546             this.firstCall = null;
   1547             this.secondCall = null;
   1548             this.thirdCall = null;
   1549             this.lastCall = null;
   1550             this.args = [];
   1551             this.returnValues = [];
   1552             this.thisValues = [];
   1553             this.exceptions = [];
   1554             this.callIds = [];
   1555             if (this.fakes) {
   1556                 for (var i = 0; i < this.fakes.length; i++) {
   1557                     this.fakes[i].reset();
   1558                 }
   1559             }
   1560         },
   1561 
   1562         create: function create(func) {
   1563             var name;
   1564 
   1565             if (typeof func != "function") {
   1566                 func = function () { };
   1567             } else {
   1568                 name = sinon.functionName(func);
   1569             }
   1570 
   1571             var proxy = createProxy(func);
   1572 
   1573             sinon.extend(proxy, spy);
   1574             delete proxy.create;
   1575             sinon.extend(proxy, func);
   1576 
   1577             proxy.reset();
   1578             proxy.prototype = func.prototype;
   1579             proxy.displayName = name || "spy";
   1580             proxy.toString = sinon.functionToString;
   1581             proxy._create = sinon.spy.create;
   1582             proxy.id = "spy#" + uuid++;
   1583 
   1584             return proxy;
   1585         },
   1586 
   1587         invoke: function invoke(func, thisValue, args) {
   1588             var matching = matchingFake(this.fakes, args);
   1589             var exception, returnValue;
   1590 
   1591             incrementCallCount.call(this);
   1592             push.call(this.thisValues, thisValue);
   1593             push.call(this.args, args);
   1594             push.call(this.callIds, callId++);
   1595 
   1596             createCallProperties.call(this);
   1597 
   1598             try {
   1599                 if (matching) {
   1600                     returnValue = matching.invoke(func, thisValue, args);
   1601                 } else {
   1602                     returnValue = (this.func || func).apply(thisValue, args);
   1603                 }
   1604 
   1605                 var thisCall = this.getCall(this.callCount - 1);
   1606                 if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
   1607                     returnValue = thisValue;
   1608                 }
   1609             } catch (e) {
   1610                 exception = e;
   1611             }
   1612 
   1613             push.call(this.exceptions, exception);
   1614             push.call(this.returnValues, returnValue);
   1615 
   1616             if (exception !== undefined) {
   1617                 throw exception;
   1618             }
   1619 
   1620             return returnValue;
   1621         },
   1622 
   1623         named: function named(name) {
   1624             this.displayName = name;
   1625             return this;
   1626         },
   1627 
   1628         getCall: function getCall(i) {
   1629             if (i < 0 || i >= this.callCount) {
   1630                 return null;
   1631             }
   1632 
   1633             return sinon.spyCall(this, this.thisValues[i], this.args[i],
   1634                                     this.returnValues[i], this.exceptions[i],
   1635                                     this.callIds[i]);
   1636         },
   1637 
   1638         getCalls: function () {
   1639             var calls = [];
   1640             var i;
   1641 
   1642             for (i = 0; i < this.callCount; i++) {
   1643                 calls.push(this.getCall(i));
   1644             }
   1645 
   1646             return calls;
   1647         },
   1648 
   1649         calledBefore: function calledBefore(spyFn) {
   1650             if (!this.called) {
   1651                 return false;
   1652             }
   1653 
   1654             if (!spyFn.called) {
   1655                 return true;
   1656             }
   1657 
   1658             return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
   1659         },
   1660 
   1661         calledAfter: function calledAfter(spyFn) {
   1662             if (!this.called || !spyFn.called) {
   1663                 return false;
   1664             }
   1665 
   1666             return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
   1667         },
   1668 
   1669         withArgs: function () {
   1670             var args = slice.call(arguments);
   1671 
   1672             if (this.fakes) {
   1673                 var match = matchingFake(this.fakes, args, true);
   1674 
   1675                 if (match) {
   1676                     return match;
   1677                 }
   1678             } else {
   1679                 this.fakes = [];
   1680             }
   1681 
   1682             var original = this;
   1683             var fake = this._create();
   1684             fake.matchingAguments = args;
   1685             fake.parent = this;
   1686             push.call(this.fakes, fake);
   1687 
   1688             fake.withArgs = function () {
   1689                 return original.withArgs.apply(original, arguments);
   1690             };
   1691 
   1692             for (var i = 0; i < this.args.length; i++) {
   1693                 if (fake.matches(this.args[i])) {
   1694                     incrementCallCount.call(fake);
   1695                     push.call(fake.thisValues, this.thisValues[i]);
   1696                     push.call(fake.args, this.args[i]);
   1697                     push.call(fake.returnValues, this.returnValues[i]);
   1698                     push.call(fake.exceptions, this.exceptions[i]);
   1699                     push.call(fake.callIds, this.callIds[i]);
   1700                 }
   1701             }
   1702             createCallProperties.call(fake);
   1703 
   1704             return fake;
   1705         },
   1706 
   1707         matches: function (args, strict) {
   1708             var margs = this.matchingAguments;
   1709 
   1710             if (margs.length <= args.length &&
   1711                 sinon.deepEqual(margs, args.slice(0, margs.length))) {
   1712                 return !strict || margs.length == args.length;
   1713             }
   1714         },
   1715 
   1716         printf: function (format) {
   1717             var spy = this;
   1718             var args = slice.call(arguments, 1);
   1719             var formatter;
   1720 
   1721             return (format || "").replace(/%(.)/g, function (match, specifyer) {
   1722                 formatter = spyApi.formatters[specifyer];
   1723 
   1724                 if (typeof formatter == "function") {
   1725                     return formatter.call(null, spy, args);
   1726                 } else if (!isNaN(parseInt(specifyer, 10))) {
   1727                     return sinon.format(args[specifyer - 1]);
   1728                 }
   1729 
   1730                 return "%" + specifyer;
   1731             });
   1732         }
   1733     };
   1734 
   1735     function delegateToCalls(method, matchAny, actual, notCalled) {
   1736         spyApi[method] = function () {
   1737             if (!this.called) {
   1738                 if (notCalled) {
   1739                     return notCalled.apply(this, arguments);
   1740                 }
   1741                 return false;
   1742             }
   1743 
   1744             var currentCall;
   1745             var matches = 0;
   1746 
   1747             for (var i = 0, l = this.callCount; i < l; i += 1) {
   1748                 currentCall = this.getCall(i);
   1749 
   1750                 if (currentCall[actual || method].apply(currentCall, arguments)) {
   1751                     matches += 1;
   1752 
   1753                     if (matchAny) {
   1754                         return true;
   1755                     }
   1756                 }
   1757             }
   1758 
   1759             return matches === this.callCount;
   1760         };
   1761     }
   1762 
   1763     delegateToCalls("calledOn", true);
   1764     delegateToCalls("alwaysCalledOn", false, "calledOn");
   1765     delegateToCalls("calledWith", true);
   1766     delegateToCalls("calledWithMatch", true);
   1767     delegateToCalls("alwaysCalledWith", false, "calledWith");
   1768     delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
   1769     delegateToCalls("calledWithExactly", true);
   1770     delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
   1771     delegateToCalls("neverCalledWith", false, "notCalledWith",
   1772         function () { return true; });
   1773     delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
   1774         function () { return true; });
   1775     delegateToCalls("threw", true);
   1776     delegateToCalls("alwaysThrew", false, "threw");
   1777     delegateToCalls("returned", true);
   1778     delegateToCalls("alwaysReturned", false, "returned");
   1779     delegateToCalls("calledWithNew", true);
   1780     delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
   1781     delegateToCalls("callArg", false, "callArgWith", function () {
   1782         throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
   1783     });
   1784     spyApi.callArgWith = spyApi.callArg;
   1785     delegateToCalls("callArgOn", false, "callArgOnWith", function () {
   1786         throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
   1787     });
   1788     spyApi.callArgOnWith = spyApi.callArgOn;
   1789     delegateToCalls("yield", false, "yield", function () {
   1790         throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
   1791     });
   1792     // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
   1793     spyApi.invokeCallback = spyApi.yield;
   1794     delegateToCalls("yieldOn", false, "yieldOn", function () {
   1795         throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
   1796     });
   1797     delegateToCalls("yieldTo", false, "yieldTo", function (property) {
   1798         throw new Error(this.toString() + " cannot yield to '" + property +
   1799             "' since it was not yet invoked.");
   1800     });
   1801     delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
   1802         throw new Error(this.toString() + " cannot yield to '" + property +
   1803             "' since it was not yet invoked.");
   1804     });
   1805 
   1806     spyApi.formatters = {
   1807         "c": function (spy) {
   1808             return sinon.timesInWords(spy.callCount);
   1809         },
   1810 
   1811         "n": function (spy) {
   1812             return spy.toString();
   1813         },
   1814 
   1815         "C": function (spy) {
   1816             var calls = [];
   1817 
   1818             for (var i = 0, l = spy.callCount; i < l; ++i) {
   1819                 var stringifiedCall = "    " + spy.getCall(i).toString();
   1820                 if (/\n/.test(calls[i - 1])) {
   1821                     stringifiedCall = "\n" + stringifiedCall;
   1822                 }
   1823                 push.call(calls, stringifiedCall);
   1824             }
   1825 
   1826             return calls.length > 0 ? "\n" + calls.join("\n") : "";
   1827         },
   1828 
   1829         "t": function (spy) {
   1830             var objects = [];
   1831 
   1832             for (var i = 0, l = spy.callCount; i < l; ++i) {
   1833                 push.call(objects, sinon.format(spy.thisValues[i]));
   1834             }
   1835 
   1836             return objects.join(", ");
   1837         },
   1838 
   1839         "*": function (spy, args) {
   1840             var formatted = [];
   1841 
   1842             for (var i = 0, l = args.length; i < l; ++i) {
   1843                 push.call(formatted, sinon.format(args[i]));
   1844             }
   1845 
   1846             return formatted.join(", ");
   1847         }
   1848     };
   1849 
   1850     sinon.extend(spy, spyApi);
   1851 
   1852     spy.spyCall = sinon.spyCall;
   1853     sinon.spy = spy;
   1854 
   1855     if (typeof define === "function" && define.amd) {
   1856         define(["module"], function(module) { module.exports = spy; });
   1857     } else if (commonJSModule) {
   1858         module.exports = spy;
   1859     }
   1860 }(typeof sinon == "object" && sinon || null));
   1861 
   1862 /**
   1863  * @depend ../sinon.js
   1864  */
   1865 /*jslint eqeqeq: false, onevar: false*/
   1866 /*global module, require, sinon, process, setImmediate, setTimeout*/
   1867 /**
   1868  * Stub behavior
   1869  *
   1870  * @author Christian Johansen (christian (at) cjohansen.no)
   1871  * @author Tim Fischbach (mail (at) timfischbach.de)
   1872  * @license BSD
   1873  *
   1874  * Copyright (c) 2010-2013 Christian Johansen
   1875  */
   1876 
   1877 (function (sinon) {
   1878     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   1879 
   1880     if (!sinon && commonJSModule) {
   1881         sinon = require("../sinon");
   1882     }
   1883 
   1884     if (!sinon) {
   1885         return;
   1886     }
   1887 
   1888     var slice = Array.prototype.slice;
   1889     var join = Array.prototype.join;
   1890     var proto;
   1891 
   1892     var nextTick = (function () {
   1893         if (typeof process === "object" && typeof process.nextTick === "function") {
   1894             return process.nextTick;
   1895         } else if (typeof setImmediate === "function") {
   1896             return setImmediate;
   1897         } else {
   1898             return function (callback) {
   1899                 setTimeout(callback, 0);
   1900             };
   1901         }
   1902     })();
   1903 
   1904     function throwsException(error, message) {
   1905         if (typeof error == "string") {
   1906             this.exception = new Error(message || "");
   1907             this.exception.name = error;
   1908         } else if (!error) {
   1909             this.exception = new Error("Error");
   1910         } else {
   1911             this.exception = error;
   1912         }
   1913 
   1914         return this;
   1915     }
   1916 
   1917     function getCallback(behavior, args) {
   1918         var callArgAt = behavior.callArgAt;
   1919 
   1920         if (callArgAt < 0) {
   1921             var callArgProp = behavior.callArgProp;
   1922 
   1923             for (var i = 0, l = args.length; i < l; ++i) {
   1924                 if (!callArgProp && typeof args[i] == "function") {
   1925                     return args[i];
   1926                 }
   1927 
   1928                 if (callArgProp && args[i] &&
   1929                     typeof args[i][callArgProp] == "function") {
   1930                     return args[i][callArgProp];
   1931                 }
   1932             }
   1933 
   1934             return null;
   1935         }
   1936 
   1937         return args[callArgAt];
   1938     }
   1939 
   1940     function getCallbackError(behavior, func, args) {
   1941         if (behavior.callArgAt < 0) {
   1942             var msg;
   1943 
   1944             if (behavior.callArgProp) {
   1945                 msg = sinon.functionName(behavior.stub) +
   1946                     " expected to yield to '" + behavior.callArgProp +
   1947                     "', but no object with such a property was passed.";
   1948             } else {
   1949                 msg = sinon.functionName(behavior.stub) +
   1950                     " expected to yield, but no callback was passed.";
   1951             }
   1952 
   1953             if (args.length > 0) {
   1954                 msg += " Received [" + join.call(args, ", ") + "]";
   1955             }
   1956 
   1957             return msg;
   1958         }
   1959 
   1960         return "argument at index " + behavior.callArgAt + " is not a function: " + func;
   1961     }
   1962 
   1963     function callCallback(behavior, args) {
   1964         if (typeof behavior.callArgAt == "number") {
   1965             var func = getCallback(behavior, args);
   1966 
   1967             if (typeof func != "function") {
   1968                 throw new TypeError(getCallbackError(behavior, func, args));
   1969             }
   1970 
   1971             if (behavior.callbackAsync) {
   1972                 nextTick(function() {
   1973                     func.apply(behavior.callbackContext, behavior.callbackArguments);
   1974                 });
   1975             } else {
   1976                 func.apply(behavior.callbackContext, behavior.callbackArguments);
   1977             }
   1978         }
   1979     }
   1980 
   1981     proto = {
   1982         create: function(stub) {
   1983             var behavior = sinon.extend({}, sinon.behavior);
   1984             delete behavior.create;
   1985             behavior.stub = stub;
   1986 
   1987             return behavior;
   1988         },
   1989 
   1990         isPresent: function() {
   1991             return (typeof this.callArgAt == 'number' ||
   1992                     this.exception ||
   1993                     typeof this.returnArgAt == 'number' ||
   1994                     this.returnThis ||
   1995                     this.returnValueDefined);
   1996         },
   1997 
   1998         invoke: function(context, args) {
   1999             callCallback(this, args);
   2000 
   2001             if (this.exception) {
   2002                 throw this.exception;
   2003             } else if (typeof this.returnArgAt == 'number') {
   2004                 return args[this.returnArgAt];
   2005             } else if (this.returnThis) {
   2006                 return context;
   2007             }
   2008 
   2009             return this.returnValue;
   2010         },
   2011 
   2012         onCall: function(index) {
   2013             return this.stub.onCall(index);
   2014         },
   2015 
   2016         onFirstCall: function() {
   2017             return this.stub.onFirstCall();
   2018         },
   2019 
   2020         onSecondCall: function() {
   2021             return this.stub.onSecondCall();
   2022         },
   2023 
   2024         onThirdCall: function() {
   2025             return this.stub.onThirdCall();
   2026         },
   2027 
   2028         withArgs: function(/* arguments */) {
   2029             throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
   2030                             'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
   2031         },
   2032 
   2033         callsArg: function callsArg(pos) {
   2034             if (typeof pos != "number") {
   2035                 throw new TypeError("argument index is not number");
   2036             }
   2037 
   2038             this.callArgAt = pos;
   2039             this.callbackArguments = [];
   2040             this.callbackContext = undefined;
   2041             this.callArgProp = undefined;
   2042             this.callbackAsync = false;
   2043 
   2044             return this;
   2045         },
   2046 
   2047         callsArgOn: function callsArgOn(pos, context) {
   2048             if (typeof pos != "number") {
   2049                 throw new TypeError("argument index is not number");
   2050             }
   2051             if (typeof context != "object") {
   2052                 throw new TypeError("argument context is not an object");
   2053             }
   2054 
   2055             this.callArgAt = pos;
   2056             this.callbackArguments = [];
   2057             this.callbackContext = context;
   2058             this.callArgProp = undefined;
   2059             this.callbackAsync = false;
   2060 
   2061             return this;
   2062         },
   2063 
   2064         callsArgWith: function callsArgWith(pos) {
   2065             if (typeof pos != "number") {
   2066                 throw new TypeError("argument index is not number");
   2067             }
   2068 
   2069             this.callArgAt = pos;
   2070             this.callbackArguments = slice.call(arguments, 1);
   2071             this.callbackContext = undefined;
   2072             this.callArgProp = undefined;
   2073             this.callbackAsync = false;
   2074 
   2075             return this;
   2076         },
   2077 
   2078         callsArgOnWith: function callsArgWith(pos, context) {
   2079             if (typeof pos != "number") {
   2080                 throw new TypeError("argument index is not number");
   2081             }
   2082             if (typeof context != "object") {
   2083                 throw new TypeError("argument context is not an object");
   2084             }
   2085 
   2086             this.callArgAt = pos;
   2087             this.callbackArguments = slice.call(arguments, 2);
   2088             this.callbackContext = context;
   2089             this.callArgProp = undefined;
   2090             this.callbackAsync = false;
   2091 
   2092             return this;
   2093         },
   2094 
   2095         yields: function () {
   2096             this.callArgAt = -1;
   2097             this.callbackArguments = slice.call(arguments, 0);
   2098             this.callbackContext = undefined;
   2099             this.callArgProp = undefined;
   2100             this.callbackAsync = false;
   2101 
   2102             return this;
   2103         },
   2104 
   2105         yieldsOn: function (context) {
   2106             if (typeof context != "object") {
   2107                 throw new TypeError("argument context is not an object");
   2108             }
   2109 
   2110             this.callArgAt = -1;
   2111             this.callbackArguments = slice.call(arguments, 1);
   2112             this.callbackContext = context;
   2113             this.callArgProp = undefined;
   2114             this.callbackAsync = false;
   2115 
   2116             return this;
   2117         },
   2118 
   2119         yieldsTo: function (prop) {
   2120             this.callArgAt = -1;
   2121             this.callbackArguments = slice.call(arguments, 1);
   2122             this.callbackContext = undefined;
   2123             this.callArgProp = prop;
   2124             this.callbackAsync = false;
   2125 
   2126             return this;
   2127         },
   2128 
   2129         yieldsToOn: function (prop, context) {
   2130             if (typeof context != "object") {
   2131                 throw new TypeError("argument context is not an object");
   2132             }
   2133 
   2134             this.callArgAt = -1;
   2135             this.callbackArguments = slice.call(arguments, 2);
   2136             this.callbackContext = context;
   2137             this.callArgProp = prop;
   2138             this.callbackAsync = false;
   2139 
   2140             return this;
   2141         },
   2142 
   2143 
   2144         "throws": throwsException,
   2145         throwsException: throwsException,
   2146 
   2147         returns: function returns(value) {
   2148             this.returnValue = value;
   2149             this.returnValueDefined = true;
   2150 
   2151             return this;
   2152         },
   2153 
   2154         returnsArg: function returnsArg(pos) {
   2155             if (typeof pos != "number") {
   2156                 throw new TypeError("argument index is not number");
   2157             }
   2158 
   2159             this.returnArgAt = pos;
   2160 
   2161             return this;
   2162         },
   2163 
   2164         returnsThis: function returnsThis() {
   2165             this.returnThis = true;
   2166 
   2167             return this;
   2168         }
   2169     };
   2170 
   2171     // create asynchronous versions of callsArg* and yields* methods
   2172     for (var method in proto) {
   2173         // need to avoid creating anotherasync versions of the newly added async methods
   2174         if (proto.hasOwnProperty(method) &&
   2175             method.match(/^(callsArg|yields)/) &&
   2176             !method.match(/Async/)) {
   2177             proto[method + 'Async'] = (function (syncFnName) {
   2178                 return function () {
   2179                     var result = this[syncFnName].apply(this, arguments);
   2180                     this.callbackAsync = true;
   2181                     return result;
   2182                 };
   2183             })(method);
   2184         }
   2185     }
   2186 
   2187     sinon.behavior = proto;
   2188 
   2189     if (typeof define === "function" && define.amd) {
   2190         define(["module"], function(module) { module.exports = proto; });
   2191     } else if (commonJSModule) {
   2192         module.exports = proto;
   2193     }
   2194 }(typeof sinon == "object" && sinon || null));
   2195 
   2196 /**
   2197  * @depend ../sinon.js
   2198  * @depend spy.js
   2199  * @depend behavior.js
   2200  */
   2201 /*jslint eqeqeq: false, onevar: false*/
   2202 /*global module, require, sinon*/
   2203 /**
   2204  * Stub functions
   2205  *
   2206  * @author Christian Johansen (christian (at) cjohansen.no)
   2207  * @license BSD
   2208  *
   2209  * Copyright (c) 2010-2013 Christian Johansen
   2210  */
   2211 
   2212 (function (sinon) {
   2213     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   2214 
   2215     if (!sinon && commonJSModule) {
   2216         sinon = require("../sinon");
   2217     }
   2218 
   2219     if (!sinon) {
   2220         return;
   2221     }
   2222 
   2223     function stub(object, property, func) {
   2224         if (!!func && typeof func != "function") {
   2225             throw new TypeError("Custom stub should be function");
   2226         }
   2227 
   2228         var wrapper;
   2229 
   2230         if (func) {
   2231             wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
   2232         } else {
   2233             wrapper = stub.create();
   2234         }
   2235 
   2236         if (!object && typeof property === "undefined") {
   2237             return sinon.stub.create();
   2238         }
   2239 
   2240         if (typeof property === "undefined" && typeof object == "object") {
   2241             for (var prop in object) {
   2242                 if (typeof object[prop] === "function") {
   2243                     stub(object, prop);
   2244                 }
   2245             }
   2246 
   2247             return object;
   2248         }
   2249 
   2250         return sinon.wrapMethod(object, property, wrapper);
   2251     }
   2252 
   2253     function getDefaultBehavior(stub) {
   2254         return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
   2255     }
   2256 
   2257     function getParentBehaviour(stub) {
   2258         return (stub.parent && getCurrentBehavior(stub.parent));
   2259     }
   2260 
   2261     function getCurrentBehavior(stub) {
   2262         var behavior = stub.behaviors[stub.callCount - 1];
   2263         return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
   2264     }
   2265 
   2266     var uuid = 0;
   2267 
   2268     sinon.extend(stub, (function () {
   2269         var proto = {
   2270             create: function create() {
   2271                 var functionStub = function () {
   2272                     return getCurrentBehavior(functionStub).invoke(this, arguments);
   2273                 };
   2274 
   2275                 functionStub.id = "stub#" + uuid++;
   2276                 var orig = functionStub;
   2277                 functionStub = sinon.spy.create(functionStub);
   2278                 functionStub.func = orig;
   2279 
   2280                 sinon.extend(functionStub, stub);
   2281                 functionStub._create = sinon.stub.create;
   2282                 functionStub.displayName = "stub";
   2283                 functionStub.toString = sinon.functionToString;
   2284 
   2285                 functionStub.defaultBehavior = null;
   2286                 functionStub.behaviors = [];
   2287 
   2288                 return functionStub;
   2289             },
   2290 
   2291             resetBehavior: function () {
   2292                 var i;
   2293 
   2294                 this.defaultBehavior = null;
   2295                 this.behaviors = [];
   2296 
   2297                 delete this.returnValue;
   2298                 delete this.returnArgAt;
   2299                 this.returnThis = false;
   2300 
   2301                 if (this.fakes) {
   2302                     for (i = 0; i < this.fakes.length; i++) {
   2303                         this.fakes[i].resetBehavior();
   2304                     }
   2305                 }
   2306             },
   2307 
   2308             onCall: function(index) {
   2309                 if (!this.behaviors[index]) {
   2310                     this.behaviors[index] = sinon.behavior.create(this);
   2311                 }
   2312 
   2313                 return this.behaviors[index];
   2314             },
   2315 
   2316             onFirstCall: function() {
   2317                 return this.onCall(0);
   2318             },
   2319 
   2320             onSecondCall: function() {
   2321                 return this.onCall(1);
   2322             },
   2323 
   2324             onThirdCall: function() {
   2325                 return this.onCall(2);
   2326             }
   2327         };
   2328 
   2329         for (var method in sinon.behavior) {
   2330             if (sinon.behavior.hasOwnProperty(method) &&
   2331                 !proto.hasOwnProperty(method) &&
   2332                 method != 'create' &&
   2333                 method != 'withArgs' &&
   2334                 method != 'invoke') {
   2335                 proto[method] = (function(behaviorMethod) {
   2336                     return function() {
   2337                         this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
   2338                         this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
   2339                         return this;
   2340                     };
   2341                 }(method));
   2342             }
   2343         }
   2344 
   2345         return proto;
   2346     }()));
   2347 
   2348     sinon.stub = stub;
   2349 
   2350     if (typeof define === "function" && define.amd) {
   2351         define(["module"], function(module) { module.exports = stub; });
   2352     } else if (commonJSModule) {
   2353         module.exports = stub;
   2354     }
   2355 }(typeof sinon == "object" && sinon || null));
   2356 
   2357 /**
   2358  * @depend ../sinon.js
   2359  * @depend stub.js
   2360  */
   2361 /*jslint eqeqeq: false, onevar: false, nomen: false*/
   2362 /*global module, require, sinon*/
   2363 /**
   2364  * Mock functions.
   2365  *
   2366  * @author Christian Johansen (christian (at) cjohansen.no)
   2367  * @license BSD
   2368  *
   2369  * Copyright (c) 2010-2013 Christian Johansen
   2370  */
   2371 
   2372 (function (sinon) {
   2373     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   2374     var push = [].push;
   2375     var match;
   2376 
   2377     if (!sinon && commonJSModule) {
   2378         sinon = require("../sinon");
   2379     }
   2380 
   2381     if (!sinon) {
   2382         return;
   2383     }
   2384 
   2385     match = sinon.match;
   2386 
   2387     if (!match && commonJSModule) {
   2388         match = require("./match");
   2389     }
   2390 
   2391     function mock(object) {
   2392         if (!object) {
   2393             return sinon.expectation.create("Anonymous mock");
   2394         }
   2395 
   2396         return mock.create(object);
   2397     }
   2398 
   2399     sinon.mock = mock;
   2400 
   2401     sinon.extend(mock, (function () {
   2402         function each(collection, callback) {
   2403             if (!collection) {
   2404                 return;
   2405             }
   2406 
   2407             for (var i = 0, l = collection.length; i < l; i += 1) {
   2408                 callback(collection[i]);
   2409             }
   2410         }
   2411 
   2412         return {
   2413             create: function create(object) {
   2414                 if (!object) {
   2415                     throw new TypeError("object is null");
   2416                 }
   2417 
   2418                 var mockObject = sinon.extend({}, mock);
   2419                 mockObject.object = object;
   2420                 delete mockObject.create;
   2421 
   2422                 return mockObject;
   2423             },
   2424 
   2425             expects: function expects(method) {
   2426                 if (!method) {
   2427                     throw new TypeError("method is falsy");
   2428                 }
   2429 
   2430                 if (!this.expectations) {
   2431                     this.expectations = {};
   2432                     this.proxies = [];
   2433                 }
   2434 
   2435                 if (!this.expectations[method]) {
   2436                     this.expectations[method] = [];
   2437                     var mockObject = this;
   2438 
   2439                     sinon.wrapMethod(this.object, method, function () {
   2440                         return mockObject.invokeMethod(method, this, arguments);
   2441                     });
   2442 
   2443                     push.call(this.proxies, method);
   2444                 }
   2445 
   2446                 var expectation = sinon.expectation.create(method);
   2447                 push.call(this.expectations[method], expectation);
   2448 
   2449                 return expectation;
   2450             },
   2451 
   2452             restore: function restore() {
   2453                 var object = this.object;
   2454 
   2455                 each(this.proxies, function (proxy) {
   2456                     if (typeof object[proxy].restore == "function") {
   2457                         object[proxy].restore();
   2458                     }
   2459                 });
   2460             },
   2461 
   2462             verify: function verify() {
   2463                 var expectations = this.expectations || {};
   2464                 var messages = [], met = [];
   2465 
   2466                 each(this.proxies, function (proxy) {
   2467                     each(expectations[proxy], function (expectation) {
   2468                         if (!expectation.met()) {
   2469                             push.call(messages, expectation.toString());
   2470                         } else {
   2471                             push.call(met, expectation.toString());
   2472                         }
   2473                     });
   2474                 });
   2475 
   2476                 this.restore();
   2477 
   2478                 if (messages.length > 0) {
   2479                     sinon.expectation.fail(messages.concat(met).join("\n"));
   2480                 } else {
   2481                     sinon.expectation.pass(messages.concat(met).join("\n"));
   2482                 }
   2483 
   2484                 return true;
   2485             },
   2486 
   2487             invokeMethod: function invokeMethod(method, thisValue, args) {
   2488                 var expectations = this.expectations && this.expectations[method];
   2489                 var length = expectations && expectations.length || 0, i;
   2490 
   2491                 for (i = 0; i < length; i += 1) {
   2492                     if (!expectations[i].met() &&
   2493                         expectations[i].allowsCall(thisValue, args)) {
   2494                         return expectations[i].apply(thisValue, args);
   2495                     }
   2496                 }
   2497 
   2498                 var messages = [], available, exhausted = 0;
   2499 
   2500                 for (i = 0; i < length; i += 1) {
   2501                     if (expectations[i].allowsCall(thisValue, args)) {
   2502                         available = available || expectations[i];
   2503                     } else {
   2504                         exhausted += 1;
   2505                     }
   2506                     push.call(messages, "    " + expectations[i].toString());
   2507                 }
   2508 
   2509                 if (exhausted === 0) {
   2510                     return available.apply(thisValue, args);
   2511                 }
   2512 
   2513                 messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
   2514                     proxy: method,
   2515                     args: args
   2516                 }));
   2517 
   2518                 sinon.expectation.fail(messages.join("\n"));
   2519             }
   2520         };
   2521     }()));
   2522 
   2523     var times = sinon.timesInWords;
   2524 
   2525     sinon.expectation = (function () {
   2526         var slice = Array.prototype.slice;
   2527         var _invoke = sinon.spy.invoke;
   2528 
   2529         function callCountInWords(callCount) {
   2530             if (callCount == 0) {
   2531                 return "never called";
   2532             } else {
   2533                 return "called " + times(callCount);
   2534             }
   2535         }
   2536 
   2537         function expectedCallCountInWords(expectation) {
   2538             var min = expectation.minCalls;
   2539             var max = expectation.maxCalls;
   2540 
   2541             if (typeof min == "number" && typeof max == "number") {
   2542                 var str = times(min);
   2543 
   2544                 if (min != max) {
   2545                     str = "at least " + str + " and at most " + times(max);
   2546                 }
   2547 
   2548                 return str;
   2549             }
   2550 
   2551             if (typeof min == "number") {
   2552                 return "at least " + times(min);
   2553             }
   2554 
   2555             return "at most " + times(max);
   2556         }
   2557 
   2558         function receivedMinCalls(expectation) {
   2559             var hasMinLimit = typeof expectation.minCalls == "number";
   2560             return !hasMinLimit || expectation.callCount >= expectation.minCalls;
   2561         }
   2562 
   2563         function receivedMaxCalls(expectation) {
   2564             if (typeof expectation.maxCalls != "number") {
   2565                 return false;
   2566             }
   2567 
   2568             return expectation.callCount == expectation.maxCalls;
   2569         }
   2570 
   2571         function verifyMatcher(possibleMatcher, arg){
   2572             if (match && match.isMatcher(possibleMatcher)) {
   2573                 return possibleMatcher.test(arg);
   2574             } else {
   2575                 return true;
   2576             }
   2577         }
   2578 
   2579         return {
   2580             minCalls: 1,
   2581             maxCalls: 1,
   2582 
   2583             create: function create(methodName) {
   2584                 var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
   2585                 delete expectation.create;
   2586                 expectation.method = methodName;
   2587 
   2588                 return expectation;
   2589             },
   2590 
   2591             invoke: function invoke(func, thisValue, args) {
   2592                 this.verifyCallAllowed(thisValue, args);
   2593 
   2594                 return _invoke.apply(this, arguments);
   2595             },
   2596 
   2597             atLeast: function atLeast(num) {
   2598                 if (typeof num != "number") {
   2599                     throw new TypeError("'" + num + "' is not number");
   2600                 }
   2601 
   2602                 if (!this.limitsSet) {
   2603                     this.maxCalls = null;
   2604                     this.limitsSet = true;
   2605                 }
   2606 
   2607                 this.minCalls = num;
   2608 
   2609                 return this;
   2610             },
   2611 
   2612             atMost: function atMost(num) {
   2613                 if (typeof num != "number") {
   2614                     throw new TypeError("'" + num + "' is not number");
   2615                 }
   2616 
   2617                 if (!this.limitsSet) {
   2618                     this.minCalls = null;
   2619                     this.limitsSet = true;
   2620                 }
   2621 
   2622                 this.maxCalls = num;
   2623 
   2624                 return this;
   2625             },
   2626 
   2627             never: function never() {
   2628                 return this.exactly(0);
   2629             },
   2630 
   2631             once: function once() {
   2632                 return this.exactly(1);
   2633             },
   2634 
   2635             twice: function twice() {
   2636                 return this.exactly(2);
   2637             },
   2638 
   2639             thrice: function thrice() {
   2640                 return this.exactly(3);
   2641             },
   2642 
   2643             exactly: function exactly(num) {
   2644                 if (typeof num != "number") {
   2645                     throw new TypeError("'" + num + "' is not a number");
   2646                 }
   2647 
   2648                 this.atLeast(num);
   2649                 return this.atMost(num);
   2650             },
   2651 
   2652             met: function met() {
   2653                 return !this.failed && receivedMinCalls(this);
   2654             },
   2655 
   2656             verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
   2657                 if (receivedMaxCalls(this)) {
   2658                     this.failed = true;
   2659                     sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
   2660                 }
   2661 
   2662                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
   2663                     sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
   2664                         this.expectedThis);
   2665                 }
   2666 
   2667                 if (!("expectedArguments" in this)) {
   2668                     return;
   2669                 }
   2670 
   2671                 if (!args) {
   2672                     sinon.expectation.fail(this.method + " received no arguments, expected " +
   2673                         sinon.format(this.expectedArguments));
   2674                 }
   2675 
   2676                 if (args.length < this.expectedArguments.length) {
   2677                     sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
   2678                         "), expected " + sinon.format(this.expectedArguments));
   2679                 }
   2680 
   2681                 if (this.expectsExactArgCount &&
   2682                     args.length != this.expectedArguments.length) {
   2683                     sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
   2684                         "), expected " + sinon.format(this.expectedArguments));
   2685                 }
   2686 
   2687                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
   2688 
   2689                     if (!verifyMatcher(this.expectedArguments[i],args[i])) {
   2690                         sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
   2691                             ", didn't match " + this.expectedArguments.toString());
   2692                     }
   2693 
   2694                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
   2695                         sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
   2696                             ", expected " + sinon.format(this.expectedArguments));
   2697                     }
   2698                 }
   2699             },
   2700 
   2701             allowsCall: function allowsCall(thisValue, args) {
   2702                 if (this.met() && receivedMaxCalls(this)) {
   2703                     return false;
   2704                 }
   2705 
   2706                 if ("expectedThis" in this && this.expectedThis !== thisValue) {
   2707                     return false;
   2708                 }
   2709 
   2710                 if (!("expectedArguments" in this)) {
   2711                     return true;
   2712                 }
   2713 
   2714                 args = args || [];
   2715 
   2716                 if (args.length < this.expectedArguments.length) {
   2717                     return false;
   2718                 }
   2719 
   2720                 if (this.expectsExactArgCount &&
   2721                     args.length != this.expectedArguments.length) {
   2722                     return false;
   2723                 }
   2724 
   2725                 for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
   2726                     if (!verifyMatcher(this.expectedArguments[i],args[i])) {
   2727                         return false;
   2728                     }
   2729 
   2730                     if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
   2731                         return false;
   2732                     }
   2733                 }
   2734 
   2735                 return true;
   2736             },
   2737 
   2738             withArgs: function withArgs() {
   2739                 this.expectedArguments = slice.call(arguments);
   2740                 return this;
   2741             },
   2742 
   2743             withExactArgs: function withExactArgs() {
   2744                 this.withArgs.apply(this, arguments);
   2745                 this.expectsExactArgCount = true;
   2746                 return this;
   2747             },
   2748 
   2749             on: function on(thisValue) {
   2750                 this.expectedThis = thisValue;
   2751                 return this;
   2752             },
   2753 
   2754             toString: function () {
   2755                 var args = (this.expectedArguments || []).slice();
   2756 
   2757                 if (!this.expectsExactArgCount) {
   2758                     push.call(args, "[...]");
   2759                 }
   2760 
   2761                 var callStr = sinon.spyCall.toString.call({
   2762                     proxy: this.method || "anonymous mock expectation",
   2763                     args: args
   2764                 });
   2765 
   2766                 var message = callStr.replace(", [...", "[, ...") + " " +
   2767                     expectedCallCountInWords(this);
   2768 
   2769                 if (this.met()) {
   2770                     return "Expectation met: " + message;
   2771                 }
   2772 
   2773                 return "Expected " + message + " (" +
   2774                     callCountInWords(this.callCount) + ")";
   2775             },
   2776 
   2777             verify: function verify() {
   2778                 if (!this.met()) {
   2779                     sinon.expectation.fail(this.toString());
   2780                 } else {
   2781                     sinon.expectation.pass(this.toString());
   2782                 }
   2783 
   2784                 return true;
   2785             },
   2786 
   2787             pass: function(message) {
   2788               sinon.assert.pass(message);
   2789             },
   2790             fail: function (message) {
   2791                 var exception = new Error(message);
   2792                 exception.name = "ExpectationError";
   2793 
   2794                 throw exception;
   2795             }
   2796         };
   2797     }());
   2798 
   2799     sinon.mock = mock;
   2800 
   2801     if (typeof define === "function" && define.amd) {
   2802         define(["module"], function(module) { module.exports = mock; });
   2803     } else if (commonJSModule) {
   2804         module.exports = mock;
   2805     }
   2806 }(typeof sinon == "object" && sinon || null));
   2807 
   2808 /**
   2809  * @depend ../sinon.js
   2810  * @depend stub.js
   2811  * @depend mock.js
   2812  */
   2813 /*jslint eqeqeq: false, onevar: false, forin: true*/
   2814 /*global module, require, sinon*/
   2815 /**
   2816  * Collections of stubs, spies and mocks.
   2817  *
   2818  * @author Christian Johansen (christian (at) cjohansen.no)
   2819  * @license BSD
   2820  *
   2821  * Copyright (c) 2010-2013 Christian Johansen
   2822  */
   2823 
   2824 (function (sinon) {
   2825     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   2826     var push = [].push;
   2827     var hasOwnProperty = Object.prototype.hasOwnProperty;
   2828 
   2829     if (!sinon && commonJSModule) {
   2830         sinon = require("../sinon");
   2831     }
   2832 
   2833     if (!sinon) {
   2834         return;
   2835     }
   2836 
   2837     function getFakes(fakeCollection) {
   2838         if (!fakeCollection.fakes) {
   2839             fakeCollection.fakes = [];
   2840         }
   2841 
   2842         return fakeCollection.fakes;
   2843     }
   2844 
   2845     function each(fakeCollection, method) {
   2846         var fakes = getFakes(fakeCollection);
   2847 
   2848         for (var i = 0, l = fakes.length; i < l; i += 1) {
   2849             if (typeof fakes[i][method] == "function") {
   2850                 fakes[i][method]();
   2851             }
   2852         }
   2853     }
   2854 
   2855     function compact(fakeCollection) {
   2856         var fakes = getFakes(fakeCollection);
   2857         var i = 0;
   2858         while (i < fakes.length) {
   2859           fakes.splice(i, 1);
   2860         }
   2861     }
   2862 
   2863     var collection = {
   2864         verify: function resolve() {
   2865             each(this, "verify");
   2866         },
   2867 
   2868         restore: function restore() {
   2869             each(this, "restore");
   2870             compact(this);
   2871         },
   2872 
   2873         verifyAndRestore: function verifyAndRestore() {
   2874             var exception;
   2875 
   2876             try {
   2877                 this.verify();
   2878             } catch (e) {
   2879                 exception = e;
   2880             }
   2881 
   2882             this.restore();
   2883 
   2884             if (exception) {
   2885                 throw exception;
   2886             }
   2887         },
   2888 
   2889         add: function add(fake) {
   2890             push.call(getFakes(this), fake);
   2891             return fake;
   2892         },
   2893 
   2894         spy: function spy() {
   2895             return this.add(sinon.spy.apply(sinon, arguments));
   2896         },
   2897 
   2898         stub: function stub(object, property, value) {
   2899             if (property) {
   2900                 var original = object[property];
   2901 
   2902                 if (typeof original != "function") {
   2903                     if (!hasOwnProperty.call(object, property)) {
   2904                         throw new TypeError("Cannot stub non-existent own property " + property);
   2905                     }
   2906 
   2907                     object[property] = value;
   2908 
   2909                     return this.add({
   2910                         restore: function () {
   2911                             object[property] = original;
   2912                         }
   2913                     });
   2914                 }
   2915             }
   2916             if (!property && !!object && typeof object == "object") {
   2917                 var stubbedObj = sinon.stub.apply(sinon, arguments);
   2918 
   2919                 for (var prop in stubbedObj) {
   2920                     if (typeof stubbedObj[prop] === "function") {
   2921                         this.add(stubbedObj[prop]);
   2922                     }
   2923                 }
   2924 
   2925                 return stubbedObj;
   2926             }
   2927 
   2928             return this.add(sinon.stub.apply(sinon, arguments));
   2929         },
   2930 
   2931         mock: function mock() {
   2932             return this.add(sinon.mock.apply(sinon, arguments));
   2933         },
   2934 
   2935         inject: function inject(obj) {
   2936             var col = this;
   2937 
   2938             obj.spy = function () {
   2939                 return col.spy.apply(col, arguments);
   2940             };
   2941 
   2942             obj.stub = function () {
   2943                 return col.stub.apply(col, arguments);
   2944             };
   2945 
   2946             obj.mock = function () {
   2947                 return col.mock.apply(col, arguments);
   2948             };
   2949 
   2950             return obj;
   2951         }
   2952     };
   2953 
   2954     sinon.collection = collection;
   2955 
   2956     if (typeof define === "function" && define.amd) {
   2957         define(["module"], function(module) { module.exports = collection; });
   2958     } else if (commonJSModule) {
   2959         module.exports = collection;
   2960     }
   2961 }(typeof sinon == "object" && sinon || null));
   2962 
   2963 /*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
   2964 /*global module, require, window*/
   2965 /**
   2966  * Fake timer API
   2967  * setTimeout
   2968  * setInterval
   2969  * clearTimeout
   2970  * clearInterval
   2971  * tick
   2972  * reset
   2973  * Date
   2974  *
   2975  * Inspired by jsUnitMockTimeOut from JsUnit
   2976  *
   2977  * @author Christian Johansen (christian (at) cjohansen.no)
   2978  * @license BSD
   2979  *
   2980  * Copyright (c) 2010-2013 Christian Johansen
   2981  */
   2982 
   2983 if (typeof sinon == "undefined") {
   2984     var sinon = {};
   2985 }
   2986 
   2987 (function (global) {
   2988     // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
   2989     // browsers, a number.
   2990     // see https://github.com/cjohansen/Sinon.JS/pull/436
   2991     var timeoutResult = setTimeout(function() {}, 0);
   2992     var addTimerReturnsObject = typeof timeoutResult === 'object';
   2993     clearTimeout(timeoutResult);
   2994 
   2995     var id = 1;
   2996 
   2997     function addTimer(args, recurring) {
   2998         if (args.length === 0) {
   2999             throw new Error("Function requires at least 1 parameter");
   3000         }
   3001 
   3002         if (typeof args[0] === "undefined") {
   3003             throw new Error("Callback must be provided to timer calls");
   3004         }
   3005 
   3006         var toId = id++;
   3007         var delay = args[1] || 0;
   3008 
   3009         if (!this.timeouts) {
   3010             this.timeouts = {};
   3011         }
   3012 
   3013         this.timeouts[toId] = {
   3014             id: toId,
   3015             func: args[0],
   3016             callAt: this.now + delay,
   3017             invokeArgs: Array.prototype.slice.call(args, 2)
   3018         };
   3019 
   3020         if (recurring === true) {
   3021             this.timeouts[toId].interval = delay;
   3022         }
   3023 
   3024         if (addTimerReturnsObject) {
   3025             return {
   3026                 id: toId,
   3027                 ref: function() {},
   3028                 unref: function() {}
   3029             };
   3030         }
   3031         else {
   3032             return toId;
   3033         }
   3034     }
   3035 
   3036     function parseTime(str) {
   3037         if (!str) {
   3038             return 0;
   3039         }
   3040 
   3041         var strings = str.split(":");
   3042         var l = strings.length, i = l;
   3043         var ms = 0, parsed;
   3044 
   3045         if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
   3046             throw new Error("tick only understands numbers and 'h:m:s'");
   3047         }
   3048 
   3049         while (i--) {
   3050             parsed = parseInt(strings[i], 10);
   3051 
   3052             if (parsed >= 60) {
   3053                 throw new Error("Invalid time " + str);
   3054             }
   3055 
   3056             ms += parsed * Math.pow(60, (l - i - 1));
   3057         }
   3058 
   3059         return ms * 1000;
   3060     }
   3061 
   3062     function createObject(object) {
   3063         var newObject;
   3064 
   3065         if (Object.create) {
   3066             newObject = Object.create(object);
   3067         } else {
   3068             var F = function () {};
   3069             F.prototype = object;
   3070             newObject = new F();
   3071         }
   3072 
   3073         newObject.Date.clock = newObject;
   3074         return newObject;
   3075     }
   3076 
   3077     sinon.clock = {
   3078         now: 0,
   3079 
   3080         create: function create(now) {
   3081             var clock = createObject(this);
   3082 
   3083             if (typeof now == "number") {
   3084                 clock.now = now;
   3085             }
   3086 
   3087             if (!!now && typeof now == "object") {
   3088                 throw new TypeError("now should be milliseconds since UNIX epoch");
   3089             }
   3090 
   3091             return clock;
   3092         },
   3093 
   3094         setTimeout: function setTimeout(callback, timeout) {
   3095             return addTimer.call(this, arguments, false);
   3096         },
   3097 
   3098         clearTimeout: function clearTimeout(timerId) {
   3099             if (!this.timeouts) {
   3100                 this.timeouts = [];
   3101             }
   3102             // in Node, timerId is an object with .ref()/.unref(), and
   3103             // its .id field is the actual timer id.
   3104             if (typeof timerId === 'object') {
   3105               timerId = timerId.id
   3106             }
   3107             if (timerId in this.timeouts) {
   3108                 delete this.timeouts[timerId];
   3109             }
   3110         },
   3111 
   3112         setInterval: function setInterval(callback, timeout) {
   3113             return addTimer.call(this, arguments, true);
   3114         },
   3115 
   3116         clearInterval: function clearInterval(timerId) {
   3117             this.clearTimeout(timerId);
   3118         },
   3119 
   3120         setImmediate: function setImmediate(callback) {
   3121             var passThruArgs = Array.prototype.slice.call(arguments, 1);
   3122 
   3123             return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
   3124         },
   3125 
   3126         clearImmediate: function clearImmediate(timerId) {
   3127             this.clearTimeout(timerId);
   3128         },
   3129 
   3130         tick: function tick(ms) {
   3131             ms = typeof ms == "number" ? ms : parseTime(ms);
   3132             var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
   3133             var timer = this.firstTimerInRange(tickFrom, tickTo);
   3134 
   3135             var firstException;
   3136             while (timer && tickFrom <= tickTo) {
   3137                 if (this.timeouts[timer.id]) {
   3138                     tickFrom = this.now = timer.callAt;
   3139                     try {
   3140                       this.callTimer(timer);
   3141                     } catch (e) {
   3142                       firstException = firstException || e;
   3143                     }
   3144                 }
   3145 
   3146                 timer = this.firstTimerInRange(previous, tickTo);
   3147                 previous = tickFrom;
   3148             }
   3149 
   3150             this.now = tickTo;
   3151 
   3152             if (firstException) {
   3153               throw firstException;
   3154             }
   3155 
   3156             return this.now;
   3157         },
   3158 
   3159         firstTimerInRange: function (from, to) {
   3160             var timer, smallest = null, originalTimer;
   3161 
   3162             for (var id in this.timeouts) {
   3163                 if (this.timeouts.hasOwnProperty(id)) {
   3164                     if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
   3165                         continue;
   3166                     }
   3167 
   3168                     if (smallest === null || this.timeouts[id].callAt < smallest) {
   3169                         originalTimer = this.timeouts[id];
   3170                         smallest = this.timeouts[id].callAt;
   3171 
   3172                         timer = {
   3173                             func: this.timeouts[id].func,
   3174                             callAt: this.timeouts[id].callAt,
   3175                             interval: this.timeouts[id].interval,
   3176                             id: this.timeouts[id].id,
   3177                             invokeArgs: this.timeouts[id].invokeArgs
   3178                         };
   3179                     }
   3180                 }
   3181             }
   3182 
   3183             return timer || null;
   3184         },
   3185 
   3186         callTimer: function (timer) {
   3187             if (typeof timer.interval == "number") {
   3188                 this.timeouts[timer.id].callAt += timer.interval;
   3189             } else {
   3190                 delete this.timeouts[timer.id];
   3191             }
   3192 
   3193             try {
   3194                 if (typeof timer.func == "function") {
   3195                     timer.func.apply(null, timer.invokeArgs);
   3196                 } else {
   3197                     eval(timer.func);
   3198                 }
   3199             } catch (e) {
   3200               var exception = e;
   3201             }
   3202 
   3203             if (!this.timeouts[timer.id]) {
   3204                 if (exception) {
   3205                   throw exception;
   3206                 }
   3207                 return;
   3208             }
   3209 
   3210             if (exception) {
   3211               throw exception;
   3212             }
   3213         },
   3214 
   3215         reset: function reset() {
   3216             this.timeouts = {};
   3217         },
   3218 
   3219         Date: (function () {
   3220             var NativeDate = Date;
   3221 
   3222             function ClockDate(year, month, date, hour, minute, second, ms) {
   3223                 // Defensive and verbose to avoid potential harm in passing
   3224                 // explicit undefined when user does not pass argument
   3225                 switch (arguments.length) {
   3226                 case 0:
   3227                     return new NativeDate(ClockDate.clock.now);
   3228                 case 1:
   3229                     return new NativeDate(year);
   3230                 case 2:
   3231                     return new NativeDate(year, month);
   3232                 case 3:
   3233                     return new NativeDate(year, month, date);
   3234                 case 4:
   3235                     return new NativeDate(year, month, date, hour);
   3236                 case 5:
   3237                     return new NativeDate(year, month, date, hour, minute);
   3238                 case 6:
   3239                     return new NativeDate(year, month, date, hour, minute, second);
   3240                 default:
   3241                     return new NativeDate(year, month, date, hour, minute, second, ms);
   3242                 }
   3243             }
   3244 
   3245             return mirrorDateProperties(ClockDate, NativeDate);
   3246         }())
   3247     };
   3248 
   3249     function mirrorDateProperties(target, source) {
   3250         if (source.now) {
   3251             target.now = function now() {
   3252                 return target.clock.now;
   3253             };
   3254         } else {
   3255             delete target.now;
   3256         }
   3257 
   3258         if (source.toSource) {
   3259             target.toSource = function toSource() {
   3260                 return source.toSource();
   3261             };
   3262         } else {
   3263             delete target.toSource;
   3264         }
   3265 
   3266         target.toString = function toString() {
   3267             return source.toString();
   3268         };
   3269 
   3270         target.prototype = source.prototype;
   3271         target.parse = source.parse;
   3272         target.UTC = source.UTC;
   3273         target.prototype.toUTCString = source.prototype.toUTCString;
   3274 
   3275         for (var prop in source) {
   3276             if (source.hasOwnProperty(prop)) {
   3277                 target[prop] = source[prop];
   3278             }
   3279         }
   3280 
   3281         return target;
   3282     }
   3283 
   3284     var methods = ["Date", "setTimeout", "setInterval",
   3285                    "clearTimeout", "clearInterval"];
   3286 
   3287     if (typeof global.setImmediate !== "undefined") {
   3288         methods.push("setImmediate");
   3289     }
   3290 
   3291     if (typeof global.clearImmediate !== "undefined") {
   3292         methods.push("clearImmediate");
   3293     }
   3294 
   3295     function restore() {
   3296         var method;
   3297 
   3298         for (var i = 0, l = this.methods.length; i < l; i++) {
   3299             method = this.methods[i];
   3300 
   3301             if (global[method].hadOwnProperty) {
   3302                 global[method] = this["_" + method];
   3303             } else {
   3304                 try {
   3305                     delete global[method];
   3306                 } catch (e) {}
   3307             }
   3308         }
   3309 
   3310         // Prevent multiple executions which will completely remove these props
   3311         this.methods = [];
   3312     }
   3313 
   3314     function stubGlobal(method, clock) {
   3315         clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
   3316         clock["_" + method] = global[method];
   3317 
   3318         if (method == "Date") {
   3319             var date = mirrorDateProperties(clock[method], global[method]);
   3320             global[method] = date;
   3321         } else {
   3322             global[method] = function () {
   3323                 return clock[method].apply(clock, arguments);
   3324             };
   3325 
   3326             for (var prop in clock[method]) {
   3327                 if (clock[method].hasOwnProperty(prop)) {
   3328                     global[method][prop] = clock[method][prop];
   3329                 }
   3330             }
   3331         }
   3332 
   3333         global[method].clock = clock;
   3334     }
   3335 
   3336     sinon.useFakeTimers = function useFakeTimers(now) {
   3337         var clock = sinon.clock.create(now);
   3338         clock.restore = restore;
   3339         clock.methods = Array.prototype.slice.call(arguments,
   3340                                                    typeof now == "number" ? 1 : 0);
   3341 
   3342         if (clock.methods.length === 0) {
   3343             clock.methods = methods;
   3344         }
   3345 
   3346         for (var i = 0, l = clock.methods.length; i < l; i++) {
   3347             stubGlobal(clock.methods[i], clock);
   3348         }
   3349 
   3350         return clock;
   3351     };
   3352 }(typeof global != "undefined" && typeof global !== "function" ? global : this));
   3353 
   3354 sinon.timers = {
   3355     setTimeout: setTimeout,
   3356     clearTimeout: clearTimeout,
   3357     setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
   3358     clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
   3359     setInterval: setInterval,
   3360     clearInterval: clearInterval,
   3361     Date: Date
   3362 };
   3363 
   3364 if (typeof module !== 'undefined' && module.exports) {
   3365     module.exports = sinon;
   3366 }
   3367 
   3368 /*jslint eqeqeq: false, onevar: false*/
   3369 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
   3370 /**
   3371  * Minimal Event interface implementation
   3372  *
   3373  * Original implementation by Sven Fuchs: https://gist.github.com/995028
   3374  * Modifications and tests by Christian Johansen.
   3375  *
   3376  * @author Sven Fuchs (svenfuchs (at) artweb-design.de)
   3377  * @author Christian Johansen (christian (at) cjohansen.no)
   3378  * @license BSD
   3379  *
   3380  * Copyright (c) 2011 Sven Fuchs, Christian Johansen
   3381  */
   3382 
   3383 if (typeof sinon == "undefined") {
   3384     this.sinon = {};
   3385 }
   3386 
   3387 (function () {
   3388     var push = [].push;
   3389 
   3390     sinon.Event = function Event(type, bubbles, cancelable, target) {
   3391         this.initEvent(type, bubbles, cancelable, target);
   3392     };
   3393 
   3394     sinon.Event.prototype = {
   3395         initEvent: function(type, bubbles, cancelable, target) {
   3396             this.type = type;
   3397             this.bubbles = bubbles;
   3398             this.cancelable = cancelable;
   3399             this.target = target;
   3400         },
   3401 
   3402         stopPropagation: function () {},
   3403 
   3404         preventDefault: function () {
   3405             this.defaultPrevented = true;
   3406         }
   3407     };
   3408 
   3409     sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
   3410         this.initEvent(type, false, false, target);
   3411         this.loaded = progressEventRaw.loaded || null;
   3412         this.total = progressEventRaw.total || null;
   3413     };
   3414 
   3415     sinon.ProgressEvent.prototype = new sinon.Event();
   3416 
   3417     sinon.ProgressEvent.prototype.constructor =  sinon.ProgressEvent;
   3418 
   3419     sinon.CustomEvent = function CustomEvent(type, customData, target) {
   3420         this.initEvent(type, false, false, target);
   3421         this.detail = customData.detail || null;
   3422     };
   3423 
   3424     sinon.CustomEvent.prototype = new sinon.Event();
   3425 
   3426     sinon.CustomEvent.prototype.constructor =  sinon.CustomEvent;
   3427 
   3428     sinon.EventTarget = {
   3429         addEventListener: function addEventListener(event, listener) {
   3430             this.eventListeners = this.eventListeners || {};
   3431             this.eventListeners[event] = this.eventListeners[event] || [];
   3432             push.call(this.eventListeners[event], listener);
   3433         },
   3434 
   3435         removeEventListener: function removeEventListener(event, listener) {
   3436             var listeners = this.eventListeners && this.eventListeners[event] || [];
   3437 
   3438             for (var i = 0, l = listeners.length; i < l; ++i) {
   3439                 if (listeners[i] == listener) {
   3440                     return listeners.splice(i, 1);
   3441                 }
   3442             }
   3443         },
   3444 
   3445         dispatchEvent: function dispatchEvent(event) {
   3446             var type = event.type;
   3447             var listeners = this.eventListeners && this.eventListeners[type] || [];
   3448 
   3449             for (var i = 0; i < listeners.length; i++) {
   3450                 if (typeof listeners[i] == "function") {
   3451                     listeners[i].call(this, event);
   3452                 } else {
   3453                     listeners[i].handleEvent(event);
   3454                 }
   3455             }
   3456 
   3457             return !!event.defaultPrevented;
   3458         }
   3459     };
   3460 }());
   3461 
   3462 /**
   3463  * @depend ../../sinon.js
   3464  * @depend event.js
   3465  */
   3466 /*jslint eqeqeq: false, onevar: false*/
   3467 /*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
   3468 /**
   3469  * Fake XMLHttpRequest object
   3470  *
   3471  * @author Christian Johansen (christian (at) cjohansen.no)
   3472  * @license BSD
   3473  *
   3474  * Copyright (c) 2010-2013 Christian Johansen
   3475  */
   3476 
   3477 // wrapper for global
   3478 (function(global) {
   3479     if (typeof sinon === "undefined") {
   3480         global.sinon = {};
   3481     }
   3482 
   3483     var supportsProgress = typeof ProgressEvent !== "undefined";
   3484     var supportsCustomEvent = typeof CustomEvent !== "undefined";
   3485     sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
   3486     var xhr = sinon.xhr;
   3487     xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
   3488     xhr.GlobalActiveXObject = global.ActiveXObject;
   3489     xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
   3490     xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
   3491     xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
   3492                                      ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
   3493     xhr.supportsCORS = 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
   3494 
   3495     /*jsl:ignore*/
   3496     var unsafeHeaders = {
   3497         "Accept-Charset": true,
   3498         "Accept-Encoding": true,
   3499         "Connection": true,
   3500         "Content-Length": true,
   3501         "Cookie": true,
   3502         "Cookie2": true,
   3503         "Content-Transfer-Encoding": true,
   3504         "Date": true,
   3505         "Expect": true,
   3506         "Host": true,
   3507         "Keep-Alive": true,
   3508         "Referer": true,
   3509         "TE": true,
   3510         "Trailer": true,
   3511         "Transfer-Encoding": true,
   3512         "Upgrade": true,
   3513         "User-Agent": true,
   3514         "Via": true
   3515     };
   3516     /*jsl:end*/
   3517 
   3518     function FakeXMLHttpRequest() {
   3519         this.readyState = FakeXMLHttpRequest.UNSENT;
   3520         this.requestHeaders = {};
   3521         this.requestBody = null;
   3522         this.status = 0;
   3523         this.statusText = "";
   3524         this.upload = new UploadProgress();
   3525         if (sinon.xhr.supportsCORS) {
   3526             this.withCredentials = false;
   3527         }
   3528 
   3529 
   3530         var xhr = this;
   3531         var events = ["loadstart", "load", "abort", "loadend"];
   3532 
   3533         function addEventListener(eventName) {
   3534             xhr.addEventListener(eventName, function (event) {
   3535                 var listener = xhr["on" + eventName];
   3536 
   3537                 if (listener && typeof listener == "function") {
   3538                     listener.call(this, event);
   3539                 }
   3540             });
   3541         }
   3542 
   3543         for (var i = events.length - 1; i >= 0; i--) {
   3544             addEventListener(events[i]);
   3545         }
   3546 
   3547         if (typeof FakeXMLHttpRequest.onCreate == "function") {
   3548             FakeXMLHttpRequest.onCreate(this);
   3549         }
   3550     }
   3551 
   3552     // An upload object is created for each
   3553     // FakeXMLHttpRequest and allows upload
   3554     // events to be simulated using uploadProgress
   3555     // and uploadError.
   3556     function UploadProgress() {
   3557         this.eventListeners = {
   3558             "progress": [],
   3559             "load": [],
   3560             "abort": [],
   3561             "error": []
   3562         }
   3563     }
   3564 
   3565     UploadProgress.prototype.addEventListener = function(event, listener) {
   3566         this.eventListeners[event].push(listener);
   3567     };
   3568 
   3569     UploadProgress.prototype.removeEventListener = function(event, listener) {
   3570         var listeners = this.eventListeners[event] || [];
   3571 
   3572         for (var i = 0, l = listeners.length; i < l; ++i) {
   3573             if (listeners[i] == listener) {
   3574                 return listeners.splice(i, 1);
   3575             }
   3576         }
   3577     };
   3578 
   3579     UploadProgress.prototype.dispatchEvent = function(event) {
   3580         var listeners = this.eventListeners[event.type] || [];
   3581 
   3582         for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
   3583             listener(event);
   3584         }
   3585     };
   3586 
   3587     function verifyState(xhr) {
   3588         if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
   3589             throw new Error("INVALID_STATE_ERR");
   3590         }
   3591 
   3592         if (xhr.sendFlag) {
   3593             throw new Error("INVALID_STATE_ERR");
   3594         }
   3595     }
   3596 
   3597     // filtering to enable a white-list version of Sinon FakeXhr,
   3598     // where whitelisted requests are passed through to real XHR
   3599     function each(collection, callback) {
   3600         if (!collection) return;
   3601         for (var i = 0, l = collection.length; i < l; i += 1) {
   3602             callback(collection[i]);
   3603         }
   3604     }
   3605     function some(collection, callback) {
   3606         for (var index = 0; index < collection.length; index++) {
   3607             if(callback(collection[index]) === true) return true;
   3608         }
   3609         return false;
   3610     }
   3611     // largest arity in XHR is 5 - XHR#open
   3612     var apply = function(obj,method,args) {
   3613         switch(args.length) {
   3614         case 0: return obj[method]();
   3615         case 1: return obj[method](args[0]);
   3616         case 2: return obj[method](args[0],args[1]);
   3617         case 3: return obj[method](args[0],args[1],args[2]);
   3618         case 4: return obj[method](args[0],args[1],args[2],args[3]);
   3619         case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
   3620         }
   3621     };
   3622 
   3623     FakeXMLHttpRequest.filters = [];
   3624     FakeXMLHttpRequest.addFilter = function(fn) {
   3625         this.filters.push(fn)
   3626     };
   3627     var IE6Re = /MSIE 6/;
   3628     FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
   3629         var xhr = new sinon.xhr.workingXHR();
   3630         each(["open","setRequestHeader","send","abort","getResponseHeader",
   3631               "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
   3632              function(method) {
   3633                  fakeXhr[method] = function() {
   3634                    return apply(xhr,method,arguments);
   3635                  };
   3636              });
   3637 
   3638         var copyAttrs = function(args) {
   3639             each(args, function(attr) {
   3640               try {
   3641                 fakeXhr[attr] = xhr[attr]
   3642               } catch(e) {
   3643                 if(!IE6Re.test(navigator.userAgent)) throw e;
   3644               }
   3645             });
   3646         };
   3647 
   3648         var stateChange = function() {
   3649             fakeXhr.readyState = xhr.readyState;
   3650             if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
   3651                 copyAttrs(["status","statusText"]);
   3652             }
   3653             if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
   3654                 copyAttrs(["responseText"]);
   3655             }
   3656             if(xhr.readyState === FakeXMLHttpRequest.DONE) {
   3657                 copyAttrs(["responseXML"]);
   3658             }
   3659             if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
   3660         };
   3661         if(xhr.addEventListener) {
   3662           for(var event in fakeXhr.eventListeners) {
   3663               if(fakeXhr.eventListeners.hasOwnProperty(event)) {
   3664                   each(fakeXhr.eventListeners[event],function(handler) {
   3665                       xhr.addEventListener(event, handler);
   3666                   });
   3667               }
   3668           }
   3669           xhr.addEventListener("readystatechange",stateChange);
   3670         } else {
   3671           xhr.onreadystatechange = stateChange;
   3672         }
   3673         apply(xhr,"open",xhrArgs);
   3674     };
   3675     FakeXMLHttpRequest.useFilters = false;
   3676 
   3677     function verifyRequestOpened(xhr) {
   3678         if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
   3679             throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
   3680         }
   3681     }
   3682 
   3683     function verifyRequestSent(xhr) {
   3684         if (xhr.readyState == FakeXMLHttpRequest.DONE) {
   3685             throw new Error("Request done");
   3686         }
   3687     }
   3688 
   3689     function verifyHeadersReceived(xhr) {
   3690         if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
   3691             throw new Error("No headers received");
   3692         }
   3693     }
   3694 
   3695     function verifyResponseBodyType(body) {
   3696         if (typeof body != "string") {
   3697             var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
   3698                                  body + ", which is not a string.");
   3699             error.name = "InvalidBodyException";
   3700             throw error;
   3701         }
   3702     }
   3703 
   3704     sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
   3705         async: true,
   3706 
   3707         open: function open(method, url, async, username, password) {
   3708             this.method = method;
   3709             this.url = url;
   3710             this.async = typeof async == "boolean" ? async : true;
   3711             this.username = username;
   3712             this.password = password;
   3713             this.responseText = null;
   3714             this.responseXML = null;
   3715             this.requestHeaders = {};
   3716             this.sendFlag = false;
   3717             if(sinon.FakeXMLHttpRequest.useFilters === true) {
   3718                 var xhrArgs = arguments;
   3719                 var defake = some(FakeXMLHttpRequest.filters,function(filter) {
   3720                     return filter.apply(this,xhrArgs)
   3721                 });
   3722                 if (defake) {
   3723                   return sinon.FakeXMLHttpRequest.defake(this,arguments);
   3724                 }
   3725             }
   3726             this.readyStateChange(FakeXMLHttpRequest.OPENED);
   3727         },
   3728 
   3729         readyStateChange: function readyStateChange(state) {
   3730             this.readyState = state;
   3731 
   3732             if (typeof this.onreadystatechange == "function") {
   3733                 try {
   3734                     this.onreadystatechange();
   3735                 } catch (e) {
   3736                     sinon.logError("Fake XHR onreadystatechange handler", e);
   3737                 }
   3738             }
   3739 
   3740             this.dispatchEvent(new sinon.Event("readystatechange"));
   3741 
   3742             switch (this.readyState) {
   3743                 case FakeXMLHttpRequest.DONE:
   3744                     this.dispatchEvent(new sinon.Event("load", false, false, this));
   3745                     this.dispatchEvent(new sinon.Event("loadend", false, false, this));
   3746                     this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
   3747                     if (supportsProgress) {
   3748                         this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
   3749                     }
   3750                     break;
   3751             }
   3752         },
   3753 
   3754         setRequestHeader: function setRequestHeader(header, value) {
   3755             verifyState(this);
   3756 
   3757             if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
   3758                 throw new Error("Refused to set unsafe header \"" + header + "\"");
   3759             }
   3760 
   3761             if (this.requestHeaders[header]) {
   3762                 this.requestHeaders[header] += "," + value;
   3763             } else {
   3764                 this.requestHeaders[header] = value;
   3765             }
   3766         },
   3767 
   3768         // Helps testing
   3769         setResponseHeaders: function setResponseHeaders(headers) {
   3770             verifyRequestOpened(this);
   3771             this.responseHeaders = {};
   3772 
   3773             for (var header in headers) {
   3774                 if (headers.hasOwnProperty(header)) {
   3775                     this.responseHeaders[header] = headers[header];
   3776                 }
   3777             }
   3778 
   3779             if (this.async) {
   3780                 this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
   3781             } else {
   3782                 this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
   3783             }
   3784         },
   3785 
   3786         // Currently treats ALL data as a DOMString (i.e. no Document)
   3787         send: function send(data) {
   3788             verifyState(this);
   3789 
   3790             if (!/^(get|head)$/i.test(this.method)) {
   3791                 if (this.requestHeaders["Content-Type"]) {
   3792                     var value = this.requestHeaders["Content-Type"].split(";");
   3793                     this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
   3794                 } else {
   3795                     this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
   3796                 }
   3797 
   3798                 this.requestBody = data;
   3799             }
   3800 
   3801             this.errorFlag = false;
   3802             this.sendFlag = this.async;
   3803             this.readyStateChange(FakeXMLHttpRequest.OPENED);
   3804 
   3805             if (typeof this.onSend == "function") {
   3806                 this.onSend(this);
   3807             }
   3808 
   3809             this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
   3810         },
   3811 
   3812         abort: function abort() {
   3813             this.aborted = true;
   3814             this.responseText = null;
   3815             this.errorFlag = true;
   3816             this.requestHeaders = {};
   3817 
   3818             if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
   3819                 this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
   3820                 this.sendFlag = false;
   3821             }
   3822 
   3823             this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
   3824 
   3825             this.dispatchEvent(new sinon.Event("abort", false, false, this));
   3826 
   3827             this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
   3828 
   3829             if (typeof this.onerror === "function") {
   3830                 this.onerror();
   3831             }
   3832         },
   3833 
   3834         getResponseHeader: function getResponseHeader(header) {
   3835             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
   3836                 return null;
   3837             }
   3838 
   3839             if (/^Set-Cookie2?$/i.test(header)) {
   3840                 return null;
   3841             }
   3842 
   3843             header = header.toLowerCase();
   3844 
   3845             for (var h in this.responseHeaders) {
   3846                 if (h.toLowerCase() == header) {
   3847                     return this.responseHeaders[h];
   3848                 }
   3849             }
   3850 
   3851             return null;
   3852         },
   3853 
   3854         getAllResponseHeaders: function getAllResponseHeaders() {
   3855             if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
   3856                 return "";
   3857             }
   3858 
   3859             var headers = "";
   3860 
   3861             for (var header in this.responseHeaders) {
   3862                 if (this.responseHeaders.hasOwnProperty(header) &&
   3863                     !/^Set-Cookie2?$/i.test(header)) {
   3864                     headers += header + ": " + this.responseHeaders[header] + "\r\n";
   3865                 }
   3866             }
   3867 
   3868             return headers;
   3869         },
   3870 
   3871         setResponseBody: function setResponseBody(body) {
   3872             verifyRequestSent(this);
   3873             verifyHeadersReceived(this);
   3874             verifyResponseBodyType(body);
   3875 
   3876             var chunkSize = this.chunkSize || 10;
   3877             var index = 0;
   3878             this.responseText = "";
   3879 
   3880             do {
   3881                 if (this.async) {
   3882                     this.readyStateChange(FakeXMLHttpRequest.LOADING);
   3883                 }
   3884 
   3885                 this.responseText += body.substring(index, index + chunkSize);
   3886                 index += chunkSize;
   3887             } while (index < body.length);
   3888 
   3889             var type = this.getResponseHeader("Content-Type");
   3890 
   3891             if (this.responseText &&
   3892                 (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
   3893                 try {
   3894                     this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
   3895                 } catch (e) {
   3896                     // Unable to parse XML - no biggie
   3897                 }
   3898             }
   3899 
   3900             if (this.async) {
   3901                 this.readyStateChange(FakeXMLHttpRequest.DONE);
   3902             } else {
   3903                 this.readyState = FakeXMLHttpRequest.DONE;
   3904             }
   3905         },
   3906 
   3907         respond: function respond(status, headers, body) {
   3908             this.status = typeof status == "number" ? status : 200;
   3909             this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
   3910             this.setResponseHeaders(headers || {});
   3911             this.setResponseBody(body || "");
   3912         },
   3913 
   3914         uploadProgress: function uploadProgress(progressEventRaw) {
   3915             if (supportsProgress) {
   3916                 this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
   3917             }
   3918         },
   3919 
   3920         uploadError: function uploadError(error) {
   3921             if (supportsCustomEvent) {
   3922                 this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
   3923             }
   3924         }
   3925     });
   3926 
   3927     sinon.extend(FakeXMLHttpRequest, {
   3928         UNSENT: 0,
   3929         OPENED: 1,
   3930         HEADERS_RECEIVED: 2,
   3931         LOADING: 3,
   3932         DONE: 4
   3933     });
   3934 
   3935     // Borrowed from JSpec
   3936     FakeXMLHttpRequest.parseXML = function parseXML(text) {
   3937         var xmlDoc;
   3938 
   3939         if (typeof DOMParser != "undefined") {
   3940             var parser = new DOMParser();
   3941             xmlDoc = parser.parseFromString(text, "text/xml");
   3942         } else {
   3943             xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
   3944             xmlDoc.async = "false";
   3945             xmlDoc.loadXML(text);
   3946         }
   3947 
   3948         return xmlDoc;
   3949     };
   3950 
   3951     FakeXMLHttpRequest.statusCodes = {
   3952         100: "Continue",
   3953         101: "Switching Protocols",
   3954         200: "OK",
   3955         201: "Created",
   3956         202: "Accepted",
   3957         203: "Non-Authoritative Information",
   3958         204: "No Content",
   3959         205: "Reset Content",
   3960         206: "Partial Content",
   3961         300: "Multiple Choice",
   3962         301: "Moved Permanently",
   3963         302: "Found",
   3964         303: "See Other",
   3965         304: "Not Modified",
   3966         305: "Use Proxy",
   3967         307: "Temporary Redirect",
   3968         400: "Bad Request",
   3969         401: "Unauthorized",
   3970         402: "Payment Required",
   3971         403: "Forbidden",
   3972         404: "Not Found",
   3973         405: "Method Not Allowed",
   3974         406: "Not Acceptable",
   3975         407: "Proxy Authentication Required",
   3976         408: "Request Timeout",
   3977         409: "Conflict",
   3978         410: "Gone",
   3979         411: "Length Required",
   3980         412: "Precondition Failed",
   3981         413: "Request Entity Too Large",
   3982         414: "Request-URI Too Long",
   3983         415: "Unsupported Media Type",
   3984         416: "Requested Range Not Satisfiable",
   3985         417: "Expectation Failed",
   3986         422: "Unprocessable Entity",
   3987         500: "Internal Server Error",
   3988         501: "Not Implemented",
   3989         502: "Bad Gateway",
   3990         503: "Service Unavailable",
   3991         504: "Gateway Timeout",
   3992         505: "HTTP Version Not Supported"
   3993     };
   3994 
   3995     sinon.useFakeXMLHttpRequest = function () {
   3996         sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
   3997             if (xhr.supportsXHR) {
   3998                 global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
   3999             }
   4000 
   4001             if (xhr.supportsActiveX) {
   4002                 global.ActiveXObject = xhr.GlobalActiveXObject;
   4003             }
   4004 
   4005             delete sinon.FakeXMLHttpRequest.restore;
   4006 
   4007             if (keepOnCreate !== true) {
   4008                 delete sinon.FakeXMLHttpRequest.onCreate;
   4009             }
   4010         };
   4011         if (xhr.supportsXHR) {
   4012             global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
   4013         }
   4014 
   4015         if (xhr.supportsActiveX) {
   4016             global.ActiveXObject = function ActiveXObject(objId) {
   4017                 if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
   4018 
   4019                     return new sinon.FakeXMLHttpRequest();
   4020                 }
   4021 
   4022                 return new xhr.GlobalActiveXObject(objId);
   4023             };
   4024         }
   4025 
   4026         return sinon.FakeXMLHttpRequest;
   4027     };
   4028 
   4029     sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
   4030 
   4031 })(typeof global === "object" ? global : this);
   4032 
   4033 if (typeof module !== 'undefined' && module.exports) {
   4034     module.exports = sinon;
   4035 }
   4036 
   4037 /**
   4038  * @depend fake_xml_http_request.js
   4039  */
   4040 /*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
   4041 /*global module, require, window*/
   4042 /**
   4043  * The Sinon "server" mimics a web server that receives requests from
   4044  * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
   4045  * both synchronously and asynchronously. To respond synchronuously, canned
   4046  * answers have to be provided upfront.
   4047  *
   4048  * @author Christian Johansen (christian (at) cjohansen.no)
   4049  * @license BSD
   4050  *
   4051  * Copyright (c) 2010-2013 Christian Johansen
   4052  */
   4053 
   4054 if (typeof sinon == "undefined") {
   4055     var sinon = {};
   4056 }
   4057 
   4058 sinon.fakeServer = (function () {
   4059     var push = [].push;
   4060     function F() {}
   4061 
   4062     function create(proto) {
   4063         F.prototype = proto;
   4064         return new F();
   4065     }
   4066 
   4067     function responseArray(handler) {
   4068         var response = handler;
   4069 
   4070         if (Object.prototype.toString.call(handler) != "[object Array]") {
   4071             response = [200, {}, handler];
   4072         }
   4073 
   4074         if (typeof response[2] != "string") {
   4075             throw new TypeError("Fake server response body should be string, but was " +
   4076                                 typeof response[2]);
   4077         }
   4078 
   4079         return response;
   4080     }
   4081 
   4082     var wloc = typeof window !== "undefined" ? window.location : {};
   4083     var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
   4084 
   4085     function matchOne(response, reqMethod, reqUrl) {
   4086         var rmeth = response.method;
   4087         var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
   4088         var url = response.url;
   4089         var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
   4090 
   4091         return matchMethod && matchUrl;
   4092     }
   4093 
   4094     function match(response, request) {
   4095         var requestUrl = request.url;
   4096 
   4097         if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
   4098             requestUrl = requestUrl.replace(rCurrLoc, "");
   4099         }
   4100 
   4101         if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
   4102             if (typeof response.response == "function") {
   4103                 var ru = response.url;
   4104                 var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
   4105                 return response.response.apply(response, args);
   4106             }
   4107 
   4108             return true;
   4109         }
   4110 
   4111         return false;
   4112     }
   4113 
   4114     function log(response, request) {
   4115         var str;
   4116 
   4117         str =  "Request:\n"  + sinon.format(request)  + "\n\n";
   4118         str += "Response:\n" + sinon.format(response) + "\n\n";
   4119 
   4120         sinon.log(str);
   4121     }
   4122 
   4123     return {
   4124         create: function () {
   4125             var server = create(this);
   4126             this.xhr = sinon.useFakeXMLHttpRequest();
   4127             server.requests = [];
   4128 
   4129             this.xhr.onCreate = function (xhrObj) {
   4130                 server.addRequest(xhrObj);
   4131             };
   4132 
   4133             return server;
   4134         },
   4135 
   4136         addRequest: function addRequest(xhrObj) {
   4137             var server = this;
   4138             push.call(this.requests, xhrObj);
   4139 
   4140             xhrObj.onSend = function () {
   4141                 server.handleRequest(this);
   4142 
   4143                 if (server.autoRespond && !server.responding) {
   4144                     setTimeout(function () {
   4145                         server.responding = false;
   4146                         server.respond();
   4147                     }, server.autoRespondAfter || 10);
   4148 
   4149                     server.responding = true;
   4150                 }
   4151             };
   4152         },
   4153 
   4154         getHTTPMethod: function getHTTPMethod(request) {
   4155             if (this.fakeHTTPMethods && /post/i.test(request.method)) {
   4156                 var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
   4157                 return !!matches ? matches[1] : request.method;
   4158             }
   4159 
   4160             return request.method;
   4161         },
   4162 
   4163         handleRequest: function handleRequest(xhr) {
   4164             if (xhr.async) {
   4165                 if (!this.queue) {
   4166                     this.queue = [];
   4167                 }
   4168 
   4169                 push.call(this.queue, xhr);
   4170             } else {
   4171                 this.processRequest(xhr);
   4172             }
   4173         },
   4174 
   4175         respondWith: function respondWith(method, url, body) {
   4176             if (arguments.length == 1 && typeof method != "function") {
   4177                 this.response = responseArray(method);
   4178                 return;
   4179             }
   4180 
   4181             if (!this.responses) { this.responses = []; }
   4182 
   4183             if (arguments.length == 1) {
   4184                 body = method;
   4185                 url = method = null;
   4186             }
   4187 
   4188             if (arguments.length == 2) {
   4189                 body = url;
   4190                 url = method;
   4191                 method = null;
   4192             }
   4193 
   4194             push.call(this.responses, {
   4195                 method: method,
   4196                 url: url,
   4197                 response: typeof body == "function" ? body : responseArray(body)
   4198             });
   4199         },
   4200 
   4201         respond: function respond() {
   4202             if (arguments.length > 0) this.respondWith.apply(this, arguments);
   4203             var queue = this.queue || [];
   4204             var requests = queue.splice(0, queue.length);
   4205             var request;
   4206 
   4207             while(request = requests.shift()) {
   4208                 this.processRequest(request);
   4209             }
   4210         },
   4211 
   4212         processRequest: function processRequest(request) {
   4213             try {
   4214                 if (request.aborted) {
   4215                     return;
   4216                 }
   4217 
   4218                 var response = this.response || [404, {}, ""];
   4219 
   4220                 if (this.responses) {
   4221                     for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
   4222                         if (match.call(this, this.responses[i], request)) {
   4223                             response = this.responses[i].response;
   4224                             break;
   4225                         }
   4226                     }
   4227                 }
   4228 
   4229                 if (request.readyState != 4) {
   4230                     log(response, request);
   4231 
   4232                     request.respond(response[0], response[1], response[2]);
   4233                 }
   4234             } catch (e) {
   4235                 sinon.logError("Fake server request processing", e);
   4236             }
   4237         },
   4238 
   4239         restore: function restore() {
   4240             return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
   4241         }
   4242     };
   4243 }());
   4244 
   4245 if (typeof module !== 'undefined' && module.exports) {
   4246     module.exports = sinon;
   4247 }
   4248 
   4249 /**
   4250  * @depend fake_server.js
   4251  * @depend fake_timers.js
   4252  */
   4253 /*jslint browser: true, eqeqeq: false, onevar: false*/
   4254 /*global sinon*/
   4255 /**
   4256  * Add-on for sinon.fakeServer that automatically handles a fake timer along with
   4257  * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
   4258  * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
   4259  * it polls the object for completion with setInterval. Dispite the direct
   4260  * motivation, there is nothing jQuery-specific in this file, so it can be used
   4261  * in any environment where the ajax implementation depends on setInterval or
   4262  * setTimeout.
   4263  *
   4264  * @author Christian Johansen (christian (at) cjohansen.no)
   4265  * @license BSD
   4266  *
   4267  * Copyright (c) 2010-2013 Christian Johansen
   4268  */
   4269 
   4270 (function () {
   4271     function Server() {}
   4272     Server.prototype = sinon.fakeServer;
   4273 
   4274     sinon.fakeServerWithClock = new Server();
   4275 
   4276     sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
   4277         if (xhr.async) {
   4278             if (typeof setTimeout.clock == "object") {
   4279                 this.clock = setTimeout.clock;
   4280             } else {
   4281                 this.clock = sinon.useFakeTimers();
   4282                 this.resetClock = true;
   4283             }
   4284 
   4285             if (!this.longestTimeout) {
   4286                 var clockSetTimeout = this.clock.setTimeout;
   4287                 var clockSetInterval = this.clock.setInterval;
   4288                 var server = this;
   4289 
   4290                 this.clock.setTimeout = function (fn, timeout) {
   4291                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
   4292 
   4293                     return clockSetTimeout.apply(this, arguments);
   4294                 };
   4295 
   4296                 this.clock.setInterval = function (fn, timeout) {
   4297                     server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
   4298 
   4299                     return clockSetInterval.apply(this, arguments);
   4300                 };
   4301             }
   4302         }
   4303 
   4304         return sinon.fakeServer.addRequest.call(this, xhr);
   4305     };
   4306 
   4307     sinon.fakeServerWithClock.respond = function respond() {
   4308         var returnVal = sinon.fakeServer.respond.apply(this, arguments);
   4309 
   4310         if (this.clock) {
   4311             this.clock.tick(this.longestTimeout || 0);
   4312             this.longestTimeout = 0;
   4313 
   4314             if (this.resetClock) {
   4315                 this.clock.restore();
   4316                 this.resetClock = false;
   4317             }
   4318         }
   4319 
   4320         return returnVal;
   4321     };
   4322 
   4323     sinon.fakeServerWithClock.restore = function restore() {
   4324         if (this.clock) {
   4325             this.clock.restore();
   4326         }
   4327 
   4328         return sinon.fakeServer.restore.apply(this, arguments);
   4329     };
   4330 }());
   4331 
   4332 /**
   4333  * @depend ../sinon.js
   4334  * @depend collection.js
   4335  * @depend util/fake_timers.js
   4336  * @depend util/fake_server_with_clock.js
   4337  */
   4338 /*jslint eqeqeq: false, onevar: false, plusplus: false*/
   4339 /*global require, module*/
   4340 /**
   4341  * Manages fake collections as well as fake utilities such as Sinon's
   4342  * timers and fake XHR implementation in one convenient object.
   4343  *
   4344  * @author Christian Johansen (christian (at) cjohansen.no)
   4345  * @license BSD
   4346  *
   4347  * Copyright (c) 2010-2013 Christian Johansen
   4348  */
   4349 
   4350 if (typeof module !== "undefined" && module.exports && typeof require == "function") {
   4351     var sinon = require("../sinon");
   4352     sinon.extend(sinon, require("./util/fake_timers"));
   4353 }
   4354 
   4355 (function () {
   4356     var push = [].push;
   4357 
   4358     function exposeValue(sandbox, config, key, value) {
   4359         if (!value) {
   4360             return;
   4361         }
   4362 
   4363         if (config.injectInto && !(key in config.injectInto)) {
   4364             config.injectInto[key] = value;
   4365             sandbox.injectedKeys.push(key);
   4366         } else {
   4367             push.call(sandbox.args, value);
   4368         }
   4369     }
   4370 
   4371     function prepareSandboxFromConfig(config) {
   4372         var sandbox = sinon.create(sinon.sandbox);
   4373 
   4374         if (config.useFakeServer) {
   4375             if (typeof config.useFakeServer == "object") {
   4376                 sandbox.serverPrototype = config.useFakeServer;
   4377             }
   4378 
   4379             sandbox.useFakeServer();
   4380         }
   4381 
   4382         if (config.useFakeTimers) {
   4383             if (typeof config.useFakeTimers == "object") {
   4384                 sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
   4385             } else {
   4386                 sandbox.useFakeTimers();
   4387             }
   4388         }
   4389 
   4390         return sandbox;
   4391     }
   4392 
   4393     sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
   4394         useFakeTimers: function useFakeTimers() {
   4395             this.clock = sinon.useFakeTimers.apply(sinon, arguments);
   4396 
   4397             return this.add(this.clock);
   4398         },
   4399 
   4400         serverPrototype: sinon.fakeServer,
   4401 
   4402         useFakeServer: function useFakeServer() {
   4403             var proto = this.serverPrototype || sinon.fakeServer;
   4404 
   4405             if (!proto || !proto.create) {
   4406                 return null;
   4407             }
   4408 
   4409             this.server = proto.create();
   4410             return this.add(this.server);
   4411         },
   4412 
   4413         inject: function (obj) {
   4414             sinon.collection.inject.call(this, obj);
   4415 
   4416             if (this.clock) {
   4417                 obj.clock = this.clock;
   4418             }
   4419 
   4420             if (this.server) {
   4421                 obj.server = this.server;
   4422                 obj.requests = this.server.requests;
   4423             }
   4424 
   4425             return obj;
   4426         },
   4427 
   4428         restore: function () {
   4429             sinon.collection.restore.apply(this, arguments);
   4430             this.restoreContext();
   4431         },
   4432 
   4433         restoreContext: function () {
   4434             if (this.injectedKeys) {
   4435                 for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
   4436                     delete this.injectInto[this.injectedKeys[i]];
   4437                 }
   4438                 this.injectedKeys = [];
   4439             }
   4440         },
   4441 
   4442         create: function (config) {
   4443             if (!config) {
   4444                 return sinon.create(sinon.sandbox);
   4445             }
   4446 
   4447             var sandbox = prepareSandboxFromConfig(config);
   4448             sandbox.args = sandbox.args || [];
   4449             sandbox.injectedKeys = [];
   4450             sandbox.injectInto = config.injectInto;
   4451             var prop, value, exposed = sandbox.inject({});
   4452 
   4453             if (config.properties) {
   4454                 for (var i = 0, l = config.properties.length; i < l; i++) {
   4455                     prop = config.properties[i];
   4456                     value = exposed[prop] || prop == "sandbox" && sandbox;
   4457                     exposeValue(sandbox, config, prop, value);
   4458                 }
   4459             } else {
   4460                 exposeValue(sandbox, config, "sandbox", value);
   4461             }
   4462 
   4463             return sandbox;
   4464         }
   4465     });
   4466 
   4467     sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
   4468 
   4469     if (typeof define === "function" && define.amd) {
   4470         define(["module"], function(module) { module.exports = sinon.sandbox; });
   4471     } else if (typeof module !== 'undefined' && module.exports) {
   4472         module.exports = sinon.sandbox;
   4473     }
   4474 }());
   4475 
   4476 /**
   4477  * @depend ../sinon.js
   4478  * @depend stub.js
   4479  * @depend mock.js
   4480  * @depend sandbox.js
   4481  */
   4482 /*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
   4483 /*global module, require, sinon*/
   4484 /**
   4485  * Test function, sandboxes fakes
   4486  *
   4487  * @author Christian Johansen (christian (at) cjohansen.no)
   4488  * @license BSD
   4489  *
   4490  * Copyright (c) 2010-2013 Christian Johansen
   4491  */
   4492 
   4493 (function (sinon) {
   4494     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   4495 
   4496     if (!sinon && commonJSModule) {
   4497         sinon = require("../sinon");
   4498     }
   4499 
   4500     if (!sinon) {
   4501         return;
   4502     }
   4503 
   4504     function test(callback) {
   4505         var type = typeof callback;
   4506 
   4507         if (type != "function") {
   4508             throw new TypeError("sinon.test needs to wrap a test function, got " + type);
   4509         }
   4510 
   4511         return function () {
   4512             var config = sinon.getConfig(sinon.config);
   4513             config.injectInto = config.injectIntoThis && this || config.injectInto;
   4514             var sandbox = sinon.sandbox.create(config);
   4515             var exception, result;
   4516             var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
   4517 
   4518             try {
   4519                 result = callback.apply(this, args);
   4520             } catch (e) {
   4521                 exception = e;
   4522             }
   4523 
   4524             if (typeof exception !== "undefined") {
   4525                 sandbox.restore();
   4526                 throw exception;
   4527             }
   4528             else {
   4529                 sandbox.verifyAndRestore();
   4530             }
   4531 
   4532             return result;
   4533         };
   4534     }
   4535 
   4536     test.config = {
   4537         injectIntoThis: true,
   4538         injectInto: null,
   4539         properties: ["spy", "stub", "mock", "clock", "server", "requests"],
   4540         useFakeTimers: true,
   4541         useFakeServer: true
   4542     };
   4543 
   4544     sinon.test = test;
   4545 
   4546     if (typeof define === "function" && define.amd) {
   4547         define(["module"], function(module) { module.exports = test; });
   4548     } else if (commonJSModule) {
   4549         module.exports = test;
   4550     }
   4551 }(typeof sinon == "object" && sinon || null));
   4552 
   4553 /**
   4554  * @depend ../sinon.js
   4555  * @depend test.js
   4556  */
   4557 /*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
   4558 /*global module, require, sinon*/
   4559 /**
   4560  * Test case, sandboxes all test functions
   4561  *
   4562  * @author Christian Johansen (christian (at) cjohansen.no)
   4563  * @license BSD
   4564  *
   4565  * Copyright (c) 2010-2013 Christian Johansen
   4566  */
   4567 
   4568 (function (sinon) {
   4569     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   4570 
   4571     if (!sinon && commonJSModule) {
   4572         sinon = require("../sinon");
   4573     }
   4574 
   4575     if (!sinon || !Object.prototype.hasOwnProperty) {
   4576         return;
   4577     }
   4578 
   4579     function createTest(property, setUp, tearDown) {
   4580         return function () {
   4581             if (setUp) {
   4582                 setUp.apply(this, arguments);
   4583             }
   4584 
   4585             var exception, result;
   4586 
   4587             try {
   4588                 result = property.apply(this, arguments);
   4589             } catch (e) {
   4590                 exception = e;
   4591             }
   4592 
   4593             if (tearDown) {
   4594                 tearDown.apply(this, arguments);
   4595             }
   4596 
   4597             if (exception) {
   4598                 throw exception;
   4599             }
   4600 
   4601             return result;
   4602         };
   4603     }
   4604 
   4605     function testCase(tests, prefix) {
   4606         /*jsl:ignore*/
   4607         if (!tests || typeof tests != "object") {
   4608             throw new TypeError("sinon.testCase needs an object with test functions");
   4609         }
   4610         /*jsl:end*/
   4611 
   4612         prefix = prefix || "test";
   4613         var rPrefix = new RegExp("^" + prefix);
   4614         var methods = {}, testName, property, method;
   4615         var setUp = tests.setUp;
   4616         var tearDown = tests.tearDown;
   4617 
   4618         for (testName in tests) {
   4619             if (tests.hasOwnProperty(testName)) {
   4620                 property = tests[testName];
   4621 
   4622                 if (/^(setUp|tearDown)$/.test(testName)) {
   4623                     continue;
   4624                 }
   4625 
   4626                 if (typeof property == "function" && rPrefix.test(testName)) {
   4627                     method = property;
   4628 
   4629                     if (setUp || tearDown) {
   4630                         method = createTest(property, setUp, tearDown);
   4631                     }
   4632 
   4633                     methods[testName] = sinon.test(method);
   4634                 } else {
   4635                     methods[testName] = tests[testName];
   4636                 }
   4637             }
   4638         }
   4639 
   4640         return methods;
   4641     }
   4642 
   4643     sinon.testCase = testCase;
   4644 
   4645     if (typeof define === "function" && define.amd) {
   4646         define(["module"], function(module) { module.exports = testCase; });
   4647     } else if (commonJSModule) {
   4648         module.exports = testCase;
   4649     }
   4650 }(typeof sinon == "object" && sinon || null));
   4651 
   4652 /**
   4653  * @depend ../sinon.js
   4654  * @depend stub.js
   4655  */
   4656 /*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
   4657 /*global module, require, sinon*/
   4658 /**
   4659  * Assertions matching the test spy retrieval interface.
   4660  *
   4661  * @author Christian Johansen (christian (at) cjohansen.no)
   4662  * @license BSD
   4663  *
   4664  * Copyright (c) 2010-2013 Christian Johansen
   4665  */
   4666 
   4667 (function (sinon, global) {
   4668     var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
   4669     var slice = Array.prototype.slice;
   4670     var assert;
   4671 
   4672     if (!sinon && commonJSModule) {
   4673         sinon = require("../sinon");
   4674     }
   4675 
   4676     if (!sinon) {
   4677         return;
   4678     }
   4679 
   4680     function verifyIsStub() {
   4681         var method;
   4682 
   4683         for (var i = 0, l = arguments.length; i < l; ++i) {
   4684             method = arguments[i];
   4685 
   4686             if (!method) {
   4687                 assert.fail("fake is not a spy");
   4688             }
   4689 
   4690             if (typeof method != "function") {
   4691                 assert.fail(method + " is not a function");
   4692             }
   4693 
   4694             if (typeof method.getCall != "function") {
   4695                 assert.fail(method + " is not stubbed");
   4696             }
   4697         }
   4698     }
   4699 
   4700     function failAssertion(object, msg) {
   4701         object = object || global;
   4702         var failMethod = object.fail || assert.fail;
   4703         failMethod.call(object, msg);
   4704     }
   4705 
   4706     function mirrorPropAsAssertion(name, method, message) {
   4707         if (arguments.length == 2) {
   4708             message = method;
   4709             method = name;
   4710         }
   4711 
   4712         assert[name] = function (fake) {
   4713             verifyIsStub(fake);
   4714 
   4715             var args = slice.call(arguments, 1);
   4716             var failed = false;
   4717 
   4718             if (typeof method == "function") {
   4719                 failed = !method(fake);
   4720             } else {
   4721                 failed = typeof fake[method] == "function" ?
   4722                     !fake[method].apply(fake, args) : !fake[method];
   4723             }
   4724 
   4725             if (failed) {
   4726                 failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
   4727             } else {
   4728                 assert.pass(name);
   4729             }
   4730         };
   4731     }
   4732 
   4733     function exposedName(prefix, prop) {
   4734         return !prefix || /^fail/.test(prop) ? prop :
   4735             prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
   4736     }
   4737 
   4738     assert = {
   4739         failException: "AssertError",
   4740 
   4741         fail: function fail(message) {
   4742             var error = new Error(message);
   4743             error.name = this.failException || assert.failException;
   4744 
   4745             throw error;
   4746         },
   4747 
   4748         pass: function pass(assertion) {},
   4749 
   4750         callOrder: function assertCallOrder() {
   4751             verifyIsStub.apply(null, arguments);
   4752             var expected = "", actual = "";
   4753 
   4754             if (!sinon.calledInOrder(arguments)) {
   4755                 try {
   4756                     expected = [].join.call(arguments, ", ");
   4757                     var calls = slice.call(arguments);
   4758                     var i = calls.length;
   4759                     while (i) {
   4760                         if (!calls[--i].called) {
   4761                             calls.splice(i, 1);
   4762                         }
   4763                     }
   4764                     actual = sinon.orderByFirstCall(calls).join(", ");
   4765                 } catch (e) {
   4766                     // If this fails, we'll just fall back to the blank string
   4767                 }
   4768 
   4769                 failAssertion(this, "expected " + expected + " to be " +
   4770                               "called in order but were called as " + actual);
   4771             } else {
   4772                 assert.pass("callOrder");
   4773             }
   4774         },
   4775 
   4776         callCount: function assertCallCount(method, count) {
   4777             verifyIsStub(method);
   4778 
   4779             if (method.callCount != count) {
   4780                 var msg = "expected %n to be called " + sinon.timesInWords(count) +
   4781                     " but was called %c%C";
   4782                 failAssertion(this, method.printf(msg));
   4783             } else {
   4784                 assert.pass("callCount");
   4785             }
   4786         },
   4787 
   4788         expose: function expose(target, options) {
   4789             if (!target) {
   4790                 throw new TypeError("target is null or undefined");
   4791             }
   4792 
   4793             var o = options || {};
   4794             var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
   4795             var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
   4796 
   4797             for (var method in this) {
   4798                 if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
   4799                     target[exposedName(prefix, method)] = this[method];
   4800                 }
   4801             }
   4802 
   4803             return target;
   4804         },
   4805 
   4806         match: function match(actual, expectation) {
   4807             var matcher = sinon.match(expectation);
   4808             if (matcher.test(actual)) {
   4809                 assert.pass("match");
   4810             } else {
   4811                 var formatted = [
   4812                     "expected value to match",
   4813                     "    expected = " + sinon.format(expectation),
   4814                     "    actual = " + sinon.format(actual)
   4815                 ]
   4816                 failAssertion(this, formatted.join("\n"));
   4817             }
   4818         }
   4819     };
   4820 
   4821     mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
   4822     mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
   4823                           "expected %n to not have been called but was called %c%C");
   4824     mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
   4825     mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
   4826     mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
   4827     mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
   4828     mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
   4829     mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
   4830     mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
   4831     mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
   4832     mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
   4833     mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
   4834     mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
   4835     mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
   4836     mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
   4837     mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
   4838     mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
   4839     mirrorPropAsAssertion("threw", "%n did not throw exception%C");
   4840     mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
   4841 
   4842     sinon.assert = assert;
   4843 
   4844     if (typeof define === "function" && define.amd) {
   4845         define(["module"], function(module) { module.exports = assert; });
   4846     } else if (commonJSModule) {
   4847         module.exports = assert;
   4848     }
   4849 }(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
   4850 
   4851 /**
   4852  * @depend ../../sinon.js
   4853  * @depend event.js
   4854  */
   4855 /*jslint eqeqeq: false, onevar: false*/
   4856 /*global sinon, module, require, XDomainRequest*/
   4857 /**
   4858  * Fake XDomainRequest object
   4859  */
   4860 "use strict";
   4861 
   4862 if (typeof sinon == "undefined") {
   4863     this.sinon = {};
   4864 }
   4865 sinon.xdr = { XDomainRequest: this.XDomainRequest };
   4866 
   4867 // wrapper for global
   4868 (function (global) {
   4869     var xdr = sinon.xdr;
   4870     xdr.GlobalXDomainRequest = global.XDomainRequest;
   4871     xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
   4872     xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;
   4873 
   4874     function FakeXDomainRequest() {
   4875         this.readyState = FakeXDomainRequest.UNSENT;
   4876         this.requestBody = null;
   4877         this.requestHeaders = {};
   4878         this.status = 0;
   4879         this.timeout = null;
   4880 
   4881         if (typeof FakeXDomainRequest.onCreate == "function") {
   4882             FakeXDomainRequest.onCreate(this);
   4883         }
   4884     }
   4885 
   4886     function verifyState(xdr) {
   4887         if (xdr.readyState !== FakeXDomainRequest.OPENED) {
   4888             throw new Error("INVALID_STATE_ERR");
   4889         }
   4890 
   4891         if (xdr.sendFlag) {
   4892             throw new Error("INVALID_STATE_ERR");
   4893         }
   4894     }
   4895 
   4896     function verifyRequestSent(xdr) {
   4897         if (xdr.readyState == FakeXDomainRequest.UNSENT) {
   4898             throw new Error("Request not sent");
   4899         }
   4900         if (xdr.readyState == FakeXDomainRequest.DONE) {
   4901             throw new Error("Request done");
   4902         }
   4903     }
   4904 
   4905     function verifyResponseBodyType(body) {
   4906         if (typeof body != "string") {
   4907             var error = new Error("Attempted to respond to fake XDomainRequest with " +
   4908                                   body + ", which is not a string.");
   4909             error.name = "InvalidBodyException";
   4910             throw error;
   4911         }
   4912     }
   4913 
   4914     sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
   4915         open: function open(method, url) {
   4916             this.method = method;
   4917             this.url = url;
   4918 
   4919             this.responseText = null;
   4920             this.sendFlag = false;
   4921 
   4922             this.readyStateChange(FakeXDomainRequest.OPENED);
   4923         },
   4924 
   4925         readyStateChange: function readyStateChange(state) {
   4926             this.readyState = state;
   4927             var eventName = '';
   4928             switch (this.readyState) {
   4929             case FakeXDomainRequest.UNSENT:
   4930                 break;
   4931             case FakeXDomainRequest.OPENED:
   4932                 break;
   4933             case FakeXDomainRequest.LOADING:
   4934                 if (this.sendFlag){
   4935                     //raise the progress event
   4936                     eventName = 'onprogress';
   4937                 }
   4938                 break;
   4939             case FakeXDomainRequest.DONE:
   4940                 if (this.isTimeout){
   4941                     eventName = 'ontimeout'
   4942                 }
   4943                 else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
   4944                     eventName = 'onerror';
   4945                 }
   4946                 else {
   4947                     eventName = 'onload'
   4948                 }
   4949                 break;
   4950             }
   4951 
   4952             // raising event (if defined)
   4953             if (eventName) {
   4954                 if (typeof this[eventName] == "function") {
   4955                     try {
   4956                         this[eventName]();
   4957                     } catch (e) {
   4958                         sinon.logError("Fake XHR " + eventName + " handler", e);
   4959                     }
   4960                 }
   4961             }
   4962         },
   4963 
   4964         send: function send(data) {
   4965             verifyState(this);
   4966 
   4967             if (!/^(get|head)$/i.test(this.method)) {
   4968                 this.requestBody = data;
   4969             }
   4970             this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
   4971 
   4972             this.errorFlag = false;
   4973             this.sendFlag = true;
   4974             this.readyStateChange(FakeXDomainRequest.OPENED);
   4975 
   4976             if (typeof this.onSend == "function") {
   4977                 this.onSend(this);
   4978             }
   4979         },
   4980 
   4981         abort: function abort() {
   4982             this.aborted = true;
   4983             this.responseText = null;
   4984             this.errorFlag = true;
   4985 
   4986             if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
   4987                 this.readyStateChange(sinon.FakeXDomainRequest.DONE);
   4988                 this.sendFlag = false;
   4989             }
   4990         },
   4991 
   4992         setResponseBody: function setResponseBody(body) {
   4993             verifyRequestSent(this);
   4994             verifyResponseBodyType(body);
   4995 
   4996             var chunkSize = this.chunkSize || 10;
   4997             var index = 0;
   4998             this.responseText = "";
   4999 
   5000             do {
   5001                 this.readyStateChange(FakeXDomainRequest.LOADING);
   5002                 this.responseText += body.substring(index, index + chunkSize);
   5003                 index += chunkSize;
   5004             } while (index < body.length);
   5005 
   5006             this.readyStateChange(FakeXDomainRequest.DONE);
   5007         },
   5008 
   5009         respond: function respond(status, contentType, body) {
   5010             // content-type ignored, since XDomainRequest does not carry this
   5011             // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
   5012             // test integration across browsers
   5013             this.status = typeof status == "number" ? status : 200;
   5014             this.setResponseBody(body || "");
   5015         },
   5016 
   5017         simulatetimeout: function(){
   5018             this.status = 0;
   5019             this.isTimeout = true;
   5020             // Access to this should actually throw an error
   5021             this.responseText = undefined;
   5022             this.readyStateChange(FakeXDomainRequest.DONE);
   5023         }
   5024     });
   5025 
   5026     sinon.extend(FakeXDomainRequest, {
   5027         UNSENT: 0,
   5028         OPENED: 1,
   5029         LOADING: 3,
   5030         DONE: 4
   5031     });
   5032 
   5033     sinon.useFakeXDomainRequest = function () {
   5034         sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
   5035             if (xdr.supportsXDR) {
   5036                 global.XDomainRequest = xdr.GlobalXDomainRequest;
   5037             }
   5038 
   5039             delete sinon.FakeXDomainRequest.restore;
   5040 
   5041             if (keepOnCreate !== true) {
   5042                 delete sinon.FakeXDomainRequest.onCreate;
   5043             }
   5044         };
   5045         if (xdr.supportsXDR) {
   5046             global.XDomainRequest = sinon.FakeXDomainRequest;
   5047         }
   5048         return sinon.FakeXDomainRequest;
   5049     };
   5050 
   5051     sinon.FakeXDomainRequest = FakeXDomainRequest;
   5052 })(this);
   5053 
   5054 if (typeof module == "object" && typeof require == "function") {
   5055     module.exports = sinon;
   5056 }
   5057 
   5058 return sinon;}.call(typeof window != 'undefined' && window || {}));
   5059