]> source.dussan.org Git - jquery.git/commitdiff
Effects: Add tests for jQuery.Tween
authorCorey Frang <gnarf@gnarf.net>
Mon, 18 May 2015 21:11:21 +0000 (17:11 -0400)
committerCorey Frang <gnarf@gnarf.net>
Sat, 27 Jun 2015 00:05:25 +0000 (20:05 -0400)
Gruntfile.js
external/sinon/LICENSE.txt [deleted file]
external/sinon/fake_timers.js [deleted file]
external/sinon/sinon-1.14.1.js [new file with mode: 0644]
src/effects/Tween.js
src/selector-native.js
test/data/testinit.js
test/index.html
test/unit/effects.js
test/unit/tween.js [new file with mode: 0644]

index 0bf20d45423f0a3498d2ae51355302341e97dba0..8c88370e49bfa5e550bf4771ba56030d8d5c2560 100644 (file)
@@ -104,7 +104,7 @@ module.exports = function( grunt ) {
                        gruntfile: "Gruntfile.js",
 
                        // Right now, check only test helpers
-                       test: [ "test/data/testrunner.js" ],
+                       test: [ "test/data/testrunner.js", "test/unit/tween.js" ],
                        release: [ "build/*.js", "!build/release-notes.js" ],
                        tasks: "build/tasks/*.js"
                },
@@ -126,7 +126,8 @@ module.exports = function( grunt ) {
                                "selector",
                                "serialize",
                                "support",
-                               "traversing"
+                               "traversing",
+                               "tween"
                        ]
                },
                watch: {
diff --git a/external/sinon/LICENSE.txt b/external/sinon/LICENSE.txt
deleted file mode 100644 (file)
index e7f50d1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-(The BSD License)
-
-Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without modification,
-are permitted provided that the following conditions are met:
-
-    * Redistributions of source code must retain the above copyright notice,
-      this list of conditions and the following disclaimer.
-    * Redistributions in binary form must reproduce the above copyright notice,
-      this list of conditions and the following disclaimer in the documentation
-      and/or other materials provided with the distribution.
-    * Neither the name of Christian Johansen nor the names of his contributors
-      may be used to endorse or promote products derived from this software
-      without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
-ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
-FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
-CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/external/sinon/fake_timers.js b/external/sinon/fake_timers.js
deleted file mode 100644 (file)
index 0d51368..0000000
+++ /dev/null
@@ -1,409 +0,0 @@
-/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
-/*global module, require, window*/
-/**
- * Fake timer API
- * setTimeout
- * setInterval
- * clearTimeout
- * clearInterval
- * tick
- * reset
- * Date
- *
- * Inspired by jsUnitMockTimeOut from JsUnit
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-"use strict";
-
-if (typeof sinon == "undefined") {
-    var sinon = {};
-}
-
-(function (global) {
-    // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
-    // browsers, a number.
-    // see https://github.com/cjohansen/Sinon.JS/pull/436
-    var timeoutResult = setTimeout(function() {}, 0);
-    var addTimerReturnsObject = typeof timeoutResult === 'object';
-    clearTimeout(timeoutResult);
-
-    var id = 1;
-
-    function addTimer(args, recurring) {
-        if (args.length === 0) {
-            throw new Error("Function requires at least 1 parameter");
-        }
-
-        if (typeof args[0] === "undefined") {
-            throw new Error("Callback must be provided to timer calls");
-        }
-
-        var toId = id++;
-        var delay = args[1] || 0;
-
-        if (!this.timeouts) {
-            this.timeouts = {};
-        }
-
-        this.timeouts[toId] = {
-            id: toId,
-            func: args[0],
-            callAt: this.now + delay,
-            invokeArgs: Array.prototype.slice.call(args, 2)
-        };
-
-        if (recurring === true) {
-            this.timeouts[toId].interval = delay;
-        }
-
-        if (addTimerReturnsObject) {
-            return {
-                id: toId,
-                ref: function() {},
-                unref: function() {}
-            };
-        }
-        else {
-            return toId;
-        }
-    }
-
-    function parseTime(str) {
-        if (!str) {
-            return 0;
-        }
-
-        var strings = str.split(":");
-        var l = strings.length, i = l;
-        var ms = 0, parsed;
-
-        if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
-            throw new Error("tick only understands numbers and 'h:m:s'");
-        }
-
-        while (i--) {
-            parsed = parseInt(strings[i], 10);
-
-            if (parsed >= 60) {
-                throw new Error("Invalid time " + str);
-            }
-
-            ms += parsed * Math.pow(60, (l - i - 1));
-        }
-
-        return ms * 1000;
-    }
-
-    function createObject(object) {
-        var newObject;
-
-        if (Object.create) {
-            newObject = Object.create(object);
-        } else {
-            var F = function () {};
-            F.prototype = object;
-            newObject = new F();
-        }
-
-        newObject.Date.clock = newObject;
-        return newObject;
-    }
-
-    sinon.clock = {
-        now: 0,
-
-        create: function create(now) {
-            var clock = createObject(this);
-
-            if (typeof now == "number") {
-                clock.now = now;
-            }
-
-            if (!!now && typeof now == "object") {
-                throw new TypeError("now should be milliseconds since UNIX epoch");
-            }
-
-            return clock;
-        },
-
-        setTimeout: function setTimeout(callback, timeout) {
-            return addTimer.call(this, arguments, false);
-        },
-
-        clearTimeout: function clearTimeout(timerId) {
-            if (!timerId) {
-                // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel
-                return;
-            }
-            if (!this.timeouts) {
-                this.timeouts = [];
-            }
-            // in Node, timerId is an object with .ref()/.unref(), and
-            // its .id field is the actual timer id.
-            if (typeof timerId === 'object') {
-              timerId = timerId.id
-            }
-            if (timerId in this.timeouts) {
-                delete this.timeouts[timerId];
-            }
-        },
-
-        setInterval: function setInterval(callback, timeout) {
-            return addTimer.call(this, arguments, true);
-        },
-
-        clearInterval: function clearInterval(timerId) {
-            this.clearTimeout(timerId);
-        },
-
-        setImmediate: function setImmediate(callback) {
-            var passThruArgs = Array.prototype.slice.call(arguments, 1);
-
-            return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
-        },
-
-        clearImmediate: function clearImmediate(timerId) {
-            this.clearTimeout(timerId);
-        },
-
-        tick: function tick(ms) {
-            ms = typeof ms == "number" ? ms : parseTime(ms);
-            var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
-            var timer = this.firstTimerInRange(tickFrom, tickTo);
-
-            var firstException;
-            while (timer && tickFrom <= tickTo) {
-                if (this.timeouts[timer.id]) {
-                    tickFrom = this.now = timer.callAt;
-                    try {
-                      this.callTimer(timer);
-                    } catch (e) {
-                      firstException = firstException || e;
-                    }
-                }
-
-                timer = this.firstTimerInRange(previous, tickTo);
-                previous = tickFrom;
-            }
-
-            this.now = tickTo;
-
-            if (firstException) {
-              throw firstException;
-            }
-
-            return this.now;
-        },
-
-        firstTimerInRange: function (from, to) {
-            var timer, smallest = null, originalTimer;
-
-            for (var id in this.timeouts) {
-                if (this.timeouts.hasOwnProperty(id)) {
-                    if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
-                        continue;
-                    }
-
-                    if (smallest === null || this.timeouts[id].callAt < smallest) {
-                        originalTimer = this.timeouts[id];
-                        smallest = this.timeouts[id].callAt;
-
-                        timer = {
-                            func: this.timeouts[id].func,
-                            callAt: this.timeouts[id].callAt,
-                            interval: this.timeouts[id].interval,
-                            id: this.timeouts[id].id,
-                            invokeArgs: this.timeouts[id].invokeArgs
-                        };
-                    }
-                }
-            }
-
-            return timer || null;
-        },
-
-        callTimer: function (timer) {
-            if (typeof timer.interval == "number") {
-                this.timeouts[timer.id].callAt += timer.interval;
-            } else {
-                delete this.timeouts[timer.id];
-            }
-
-            try {
-                if (typeof timer.func == "function") {
-                    timer.func.apply(null, timer.invokeArgs);
-                } else {
-                    eval(timer.func);
-                }
-            } catch (e) {
-              var exception = e;
-            }
-
-            if (!this.timeouts[timer.id]) {
-                if (exception) {
-                  throw exception;
-                }
-                return;
-            }
-
-            if (exception) {
-              throw exception;
-            }
-        },
-
-        reset: function reset() {
-            this.timeouts = {};
-        },
-
-        Date: (function () {
-            var NativeDate = Date;
-
-            function ClockDate(year, month, date, hour, minute, second, ms) {
-                // Defensive and verbose to avoid potential harm in passing
-                // explicit undefined when user does not pass argument
-                switch (arguments.length) {
-                case 0:
-                    return new NativeDate(ClockDate.clock.now);
-                case 1:
-                    return new NativeDate(year);
-                case 2:
-                    return new NativeDate(year, month);
-                case 3:
-                    return new NativeDate(year, month, date);
-                case 4:
-                    return new NativeDate(year, month, date, hour);
-                case 5:
-                    return new NativeDate(year, month, date, hour, minute);
-                case 6:
-                    return new NativeDate(year, month, date, hour, minute, second);
-                default:
-                    return new NativeDate(year, month, date, hour, minute, second, ms);
-                }
-            }
-
-            return mirrorDateProperties(ClockDate, NativeDate);
-        }())
-    };
-
-    function mirrorDateProperties(target, source) {
-        if (source.now) {
-            target.now = function now() {
-                return target.clock.now;
-            };
-        } else {
-            delete target.now;
-        }
-
-        if (source.toSource) {
-            target.toSource = function toSource() {
-                return source.toSource();
-            };
-        } else {
-            delete target.toSource;
-        }
-
-        target.toString = function toString() {
-            return source.toString();
-        };
-
-        target.prototype = source.prototype;
-        target.parse = source.parse;
-        target.UTC = source.UTC;
-        target.prototype.toUTCString = source.prototype.toUTCString;
-
-        for (var prop in source) {
-            if (source.hasOwnProperty(prop)) {
-                target[prop] = source[prop];
-            }
-        }
-
-        return target;
-    }
-
-    var methods = ["Date", "setTimeout", "setInterval",
-                   "clearTimeout", "clearInterval"];
-
-    if (typeof global.setImmediate !== "undefined") {
-        methods.push("setImmediate");
-    }
-
-    if (typeof global.clearImmediate !== "undefined") {
-        methods.push("clearImmediate");
-    }
-
-    function restore() {
-        var method;
-
-        for (var i = 0, l = this.methods.length; i < l; i++) {
-            method = this.methods[i];
-
-            if (global[method].hadOwnProperty) {
-                global[method] = this["_" + method];
-            } else {
-                try {
-                    delete global[method];
-                } catch (e) {}
-            }
-        }
-
-        // Prevent multiple executions which will completely remove these props
-        this.methods = [];
-    }
-
-    function stubGlobal(method, clock) {
-        clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
-        clock["_" + method] = global[method];
-
-        if (method == "Date") {
-            var date = mirrorDateProperties(clock[method], global[method]);
-            global[method] = date;
-        } else {
-            global[method] = function () {
-                return clock[method].apply(clock, arguments);
-            };
-
-            for (var prop in clock[method]) {
-                if (clock[method].hasOwnProperty(prop)) {
-                    global[method][prop] = clock[method][prop];
-                }
-            }
-        }
-
-        global[method].clock = clock;
-    }
-
-    sinon.useFakeTimers = function useFakeTimers(now) {
-        var clock = sinon.clock.create(now);
-        clock.restore = restore;
-        clock.methods = Array.prototype.slice.call(arguments,
-                                                   typeof now == "number" ? 1 : 0);
-
-        if (clock.methods.length === 0) {
-            clock.methods = methods;
-        }
-
-        for (var i = 0, l = clock.methods.length; i < l; i++) {
-            stubGlobal(clock.methods[i], clock);
-        }
-
-        return clock;
-    };
-}(typeof global != "undefined" && typeof global !== "function" ? global : this));
-
-sinon.timers = {
-    setTimeout: setTimeout,
-    clearTimeout: clearTimeout,
-    setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
-    clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
-    setInterval: setInterval,
-    clearInterval: clearInterval,
-    Date: Date
-};
-
-if (typeof module !== 'undefined' && module.exports) {
-    module.exports = sinon;
-}
diff --git a/external/sinon/sinon-1.14.1.js b/external/sinon/sinon-1.14.1.js
new file mode 100644 (file)
index 0000000..dfbeae4
--- /dev/null
@@ -0,0 +1,5931 @@
+/**
+ * Sinon.JS 1.14.1, 2015/03/16
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
+ *
+ * (The BSD License)
+ *
+ * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ *     * Redistributions of source code must retain the above copyright notice,
+ *       this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright notice,
+ *       this list of conditions and the following disclaimer in the documentation
+ *       and/or other materials provided with the distribution.
+ *     * Neither the name of Christian Johansen nor the names of his contributors
+ *       may be used to endorse or promote products derived from this software
+ *       without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+(function (root, factory) {
+       if (typeof define === 'function' && define.amd) {
+               define('sinon', [], function () {
+                       return (root.sinon = factory());
+               });
+       } else if (typeof exports === 'object') {
+               module.exports = factory();
+       } else {
+               root.sinon = factory();
+       }
+}(this, function () {
+       var samsam, formatio;
+       (function () {
+                                                               function define(mod, deps, fn) {
+                                                                       if (mod == "samsam") {
+                                                                               samsam = deps();
+                                                                       } else if (typeof deps === "function" && mod.length === 0) {
+                                                                               lolex = deps();
+                                                                       } else if (typeof fn === "function") {
+                                                                               formatio = fn(samsam);
+                                                                       }
+                                                               }
+               define.amd = {};
+((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
+ (typeof module === "object" &&
+                       function (m) { module.exports = m(); }) || // Node
+ function (m) { this.samsam = m(); } // Browser globals
+)(function () {
+               var o = Object.prototype;
+               var div = typeof document !== "undefined" && document.createElement("div");
+
+               function isNaN(value) {
+                               // Unlike global isNaN, this avoids type coercion
+                               // typeof check avoids IE host object issues, hat tip to
+                               // lodash
+                               var val = value; // JsLint thinks value !== value is "weird"
+                               return typeof value === "number" && value !== val;
+               }
+
+               function getClass(value) {
+                               // Returns the internal [[Class]] by calling Object.prototype.toString
+                               // with the provided value as this. Return value is a string, naming the
+                               // internal class, e.g. "Array"
+                               return o.toString.call(value).split(/[ \]]/)[1];
+               }
+
+               /**
+                * @name samsam.isArguments
+                * @param Object object
+                *
+                * Returns ``true`` if ``object`` is an ``arguments`` object,
+                * ``false`` otherwise.
+                */
+               function isArguments(object) {
+                               if (getClass(object) === 'Arguments') { return true; }
+                               if (typeof object !== "object" || typeof object.length !== "number" ||
+                                                               getClass(object) === "Array") {
+                                               return false;
+                               }
+                               if (typeof object.callee == "function") { return true; }
+                               try {
+                                               object[object.length] = 6;
+                                               delete object[object.length];
+                               } catch (e) {
+                                               return true;
+                               }
+                               return false;
+               }
+
+               /**
+                * @name samsam.isElement
+                * @param Object object
+                *
+                * Returns ``true`` if ``object`` is a DOM element node. Unlike
+                * Underscore.js/lodash, this function will return ``false`` if ``object``
+                * is an *element-like* object, i.e. a regular object with a ``nodeType``
+                * property that holds the value ``1``.
+                */
+               function isElement(object) {
+                               if (!object || object.nodeType !== 1 || !div) { return false; }
+                               try {
+                                               object.appendChild(div);
+                                               object.removeChild(div);
+                               } catch (e) {
+                                               return false;
+                               }
+                               return true;
+               }
+
+               /**
+                * @name samsam.keys
+                * @param Object object
+                *
+                * Return an array of own property names.
+                */
+               function keys(object) {
+                               var ks = [], prop;
+                               for (prop in object) {
+                                               if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
+                               }
+                               return ks;
+               }
+
+               /**
+                * @name samsam.isDate
+                * @param Object value
+                *
+                * Returns true if the object is a ``Date``, or *date-like*. Duck typing
+                * of date objects work by checking that the object has a ``getTime``
+                * function whose return value equals the return value from the object's
+                * ``valueOf``.
+                */
+               function isDate(value) {
+                               return typeof value.getTime == "function" &&
+                                               value.getTime() == value.valueOf();
+               }
+
+               /**
+                * @name samsam.isNegZero
+                * @param Object value
+                *
+                * Returns ``true`` if ``value`` is ``-0``.
+                */
+               function isNegZero(value) {
+                               return value === 0 && 1 / value === -Infinity;
+               }
+
+               /**
+                * @name samsam.equal
+                * @param Object obj1
+                * @param Object obj2
+                *
+                * Returns ``true`` if two objects are strictly equal. Compared to
+                * ``===`` there are two exceptions:
+                *
+                *   - NaN is considered equal to NaN
+                *   - -0 and +0 are not considered equal
+                */
+               function identical(obj1, obj2) {
+                               if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
+                                               return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
+                               }
+               }
+
+
+               /**
+                * @name samsam.deepEqual
+                * @param Object obj1
+                * @param Object obj2
+                *
+                * Deep equal comparison. Two values are "deep equal" if:
+                *
+                *   - They are equal, according to samsam.identical
+                *   - They are both date objects representing the same time
+                *   - They are both arrays containing elements that are all deepEqual
+                *   - They are objects with the same set of properties, and each property
+                *     in ``obj1`` is deepEqual to the corresponding property in ``obj2``
+                *
+                * Supports cyclic objects.
+                */
+               function deepEqualCyclic(obj1, obj2) {
+
+                               // used for cyclic comparison
+                               // contain already visited objects
+                               var objects1 = [],
+                                               objects2 = [],
+                               // contain pathes (position in the object structure)
+                               // of the already visited objects
+                               // indexes same as in objects arrays
+                                               paths1 = [],
+                                               paths2 = [],
+                               // contains combinations of already compared objects
+                               // in the manner: { "$1['ref']$2['ref']": true }
+                                               compared = {};
+
+                               /**
+                                * used to check, if the value of a property is an object
+                                * (cyclic logic is only needed for objects)
+                                * only needed for cyclic logic
+                                */
+                               function isObject(value) {
+
+                                               if (typeof value === 'object' && value !== null &&
+                                                                               !(value instanceof Boolean) &&
+                                                                               !(value instanceof Date)    &&
+                                                                               !(value instanceof Number)  &&
+                                                                               !(value instanceof RegExp)  &&
+                                                                               !(value instanceof String)) {
+
+                                                               return true;
+                                               }
+
+                                               return false;
+                               }
+
+                               /**
+                                * returns the index of the given object in the
+                                * given objects array, -1 if not contained
+                                * only needed for cyclic logic
+                                */
+                               function getIndex(objects, obj) {
+
+                                               var i;
+                                               for (i = 0; i < objects.length; i++) {
+                                                               if (objects[i] === obj) {
+                                                                               return i;
+                                                               }
+                                               }
+
+                                               return -1;
+                               }
+
+                               // does the recursion for the deep equal check
+                               return (function deepEqual(obj1, obj2, path1, path2) {
+                                               var type1 = typeof obj1;
+                                               var type2 = typeof obj2;
+
+                                               // == null also matches undefined
+                                               if (obj1 === obj2 ||
+                                                                               isNaN(obj1) || isNaN(obj2) ||
+                                                                               obj1 == null || obj2 == null ||
+                                                                               type1 !== "object" || type2 !== "object") {
+
+                                                               return identical(obj1, obj2);
+                                               }
+
+                                               // Elements are only equal if identical(expected, actual)
+                                               if (isElement(obj1) || isElement(obj2)) { return false; }
+
+                                               var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
+                                               if (isDate1 || isDate2) {
+                                                               if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
+                                                                               return false;
+                                                               }
+                                               }
+
+                                               if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
+                                                               if (obj1.toString() !== obj2.toString()) { return false; }
+                                               }
+
+                                               var class1 = getClass(obj1);
+                                               var class2 = getClass(obj2);
+                                               var keys1 = keys(obj1);
+                                               var keys2 = keys(obj2);
+
+                                               if (isArguments(obj1) || isArguments(obj2)) {
+                                                               if (obj1.length !== obj2.length) { return false; }
+                                               } else {
+                                                               if (type1 !== type2 || class1 !== class2 ||
+                                                                                               keys1.length !== keys2.length) {
+                                                                               return false;
+                                                               }
+                                               }
+
+                                               var key, i, l,
+                                                               // following vars are used for the cyclic logic
+                                                               value1, value2,
+                                                               isObject1, isObject2,
+                                                               index1, index2,
+                                                               newPath1, newPath2;
+
+                                               for (i = 0, l = keys1.length; i < l; i++) {
+                                                               key = keys1[i];
+                                                               if (!o.hasOwnProperty.call(obj2, key)) {
+                                                                               return false;
+                                                               }
+
+                                                               // Start of the cyclic logic
+
+                                                               value1 = obj1[key];
+                                                               value2 = obj2[key];
+
+                                                               isObject1 = isObject(value1);
+                                                               isObject2 = isObject(value2);
+
+                                                               // determine, if the objects were already visited
+                                                               // (it's faster to check for isObject first, than to
+                                                               // get -1 from getIndex for non objects)
+                                                               index1 = isObject1 ? getIndex(objects1, value1) : -1;
+                                                               index2 = isObject2 ? getIndex(objects2, value2) : -1;
+
+                                                               // determine the new pathes of the objects
+                                                               // - for non cyclic objects the current path will be extended
+                                                               //   by current property name
+                                                               // - for cyclic objects the stored path is taken
+                                                               newPath1 = index1 !== -1
+                                                                               ? paths1[index1]
+                                                                               : path1 + '[' + JSON.stringify(key) + ']';
+                                                               newPath2 = index2 !== -1
+                                                                               ? paths2[index2]
+                                                                               : path2 + '[' + JSON.stringify(key) + ']';
+
+                                                               // stop recursion if current objects are already compared
+                                                               if (compared[newPath1 + newPath2]) {
+                                                                               return true;
+                                                               }
+
+                                                               // remember the current objects and their pathes
+                                                               if (index1 === -1 && isObject1) {
+                                                                               objects1.push(value1);
+                                                                               paths1.push(newPath1);
+                                                               }
+                                                               if (index2 === -1 && isObject2) {
+                                                                               objects2.push(value2);
+                                                                               paths2.push(newPath2);
+                                                               }
+
+                                                               // remember that the current objects are already compared
+                                                               if (isObject1 && isObject2) {
+                                                                               compared[newPath1 + newPath2] = true;
+                                                               }
+
+                                                               // End of cyclic logic
+
+                                                               // neither value1 nor value2 is a cycle
+                                                               // continue with next level
+                                                               if (!deepEqual(value1, value2, newPath1, newPath2)) {
+                                                                               return false;
+                                                               }
+                                               }
+
+                                               return true;
+
+                               }(obj1, obj2, '$1', '$2'));
+               }
+
+               var match;
+
+               function arrayContains(array, subset) {
+                               if (subset.length === 0) { return true; }
+                               var i, l, j, k;
+                               for (i = 0, l = array.length; i < l; ++i) {
+                                               if (match(array[i], subset[0])) {
+                                                               for (j = 0, k = subset.length; j < k; ++j) {
+                                                                               if (!match(array[i + j], subset[j])) { return false; }
+                                                               }
+                                                               return true;
+                                               }
+                               }
+                               return false;
+               }
+
+               /**
+                * @name samsam.match
+                * @param Object object
+                * @param Object matcher
+                *
+                * Compare arbitrary value ``object`` with matcher.
+                */
+               match = function match(object, matcher) {
+                               if (matcher && typeof matcher.test === "function") {
+                                               return matcher.test(object);
+                               }
+
+                               if (typeof matcher === "function") {
+                                               return matcher(object) === true;
+                               }
+
+                               if (typeof matcher === "string") {
+                                               matcher = matcher.toLowerCase();
+                                               var notNull = typeof object === "string" || !!object;
+                                               return notNull &&
+                                                               (String(object)).toLowerCase().indexOf(matcher) >= 0;
+                               }
+
+                               if (typeof matcher === "number") {
+                                               return matcher === object;
+                               }
+
+                               if (typeof matcher === "boolean") {
+                                               return matcher === object;
+                               }
+
+                               if (typeof(matcher) === "undefined") {
+                                               return typeof(object) === "undefined";
+                               }
+
+                               if (matcher === null) {
+                                               return object === null;
+                               }
+
+                               if (getClass(object) === "Array" && getClass(matcher) === "Array") {
+                                               return arrayContains(object, matcher);
+                               }
+
+                               if (matcher && typeof matcher === "object") {
+                                               if (matcher === object) {
+                                                               return true;
+                                               }
+                                               var prop;
+                                               for (prop in matcher) {
+                                                               var value = object[prop];
+                                                               if (typeof value === "undefined" &&
+                                                                                               typeof object.getAttribute === "function") {
+                                                                               value = object.getAttribute(prop);
+                                                               }
+                                                               if (matcher[prop] === null || typeof matcher[prop] === 'undefined') {
+                                                                               if (value !== matcher[prop]) {
+                                                                                               return false;
+                                                                               }
+                                                               } else if (typeof  value === "undefined" || !match(value, matcher[prop])) {
+                                                                               return false;
+                                                               }
+                                               }
+                                               return true;
+                               }
+
+                               throw new Error("Matcher was not a string, a number, a " +
+                                                                                               "function, a boolean or an object");
+               };
+
+               return {
+                               isArguments: isArguments,
+                               isElement: isElement,
+                               isDate: isDate,
+                               isNegZero: isNegZero,
+                               identical: identical,
+                               deepEqual: deepEqualCyclic,
+                               match: match,
+                               keys: keys
+               };
+});
+((typeof define === "function" && define.amd && function (m) {
+               define("formatio", ["samsam"], m);
+}) || (typeof module === "object" && function (m) {
+               module.exports = m(require("samsam"));
+}) || function (m) { this.formatio = m(this.samsam); }
+)(function (samsam) {
+
+               var formatio = {
+                               excludeConstructors: ["Object", /^.$/],
+                               quoteStrings: true,
+                               limitChildrenCount: 0
+               };
+
+               var hasOwn = Object.prototype.hasOwnProperty;
+
+               var specialObjects = [];
+               if (typeof global !== "undefined") {
+                               specialObjects.push({ object: global, value: "[object global]" });
+               }
+               if (typeof document !== "undefined") {
+                               specialObjects.push({
+                                               object: document,
+                                               value: "[object HTMLDocument]"
+                               });
+               }
+               if (typeof window !== "undefined") {
+                               specialObjects.push({ object: window, value: "[object Window]" });
+               }
+
+               function functionName(func) {
+                               if (!func) { return ""; }
+                               if (func.displayName) { return func.displayName; }
+                               if (func.name) { return func.name; }
+                               var matches = func.toString().match(/function\s+([^\(]+)/m);
+                               return (matches && matches[1]) || "";
+               }
+
+               function constructorName(f, object) {
+                               var name = functionName(object && object.constructor);
+                               var excludes = f.excludeConstructors ||
+                                                               formatio.excludeConstructors || [];
+
+                               var i, l;
+                               for (i = 0, l = excludes.length; i < l; ++i) {
+                                               if (typeof excludes[i] === "string" && excludes[i] === name) {
+                                                               return "";
+                                               } else if (excludes[i].test && excludes[i].test(name)) {
+                                                               return "";
+                                               }
+                               }
+
+                               return name;
+               }
+
+               function isCircular(object, objects) {
+                               if (typeof object !== "object") { return false; }
+                               var i, l;
+                               for (i = 0, l = objects.length; i < l; ++i) {
+                                               if (objects[i] === object) { return true; }
+                               }
+                               return false;
+               }
+
+               function ascii(f, object, processed, indent) {
+                               if (typeof object === "string") {
+                                               var qs = f.quoteStrings;
+                                               var quote = typeof qs !== "boolean" || qs;
+                                               return processed || quote ? '"' + object + '"' : object;
+                               }
+
+                               if (typeof object === "function" && !(object instanceof RegExp)) {
+                                               return ascii.func(object);
+                               }
+
+                               processed = processed || [];
+
+                               if (isCircular(object, processed)) { return "[Circular]"; }
+
+                               if (Object.prototype.toString.call(object) === "[object Array]") {
+                                               return ascii.array.call(f, object, processed);
+                               }
+
+                               if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
+                               if (samsam.isElement(object)) { return ascii.element(object); }
+
+                               if (typeof object.toString === "function" &&
+                                                               object.toString !== Object.prototype.toString) {
+                                               return object.toString();
+                               }
+
+                               var i, l;
+                               for (i = 0, l = specialObjects.length; i < l; i++) {
+                                               if (object === specialObjects[i].object) {
+                                                               return specialObjects[i].value;
+                                               }
+                               }
+
+                               return ascii.object.call(f, object, processed, indent);
+               }
+
+               ascii.func = function (func) {
+                               return "function " + functionName(func) + "() {}";
+               };
+
+               ascii.array = function (array, processed) {
+                               processed = processed || [];
+                               processed.push(array);
+                               var pieces = [];
+                               var i, l;
+                               l = (this.limitChildrenCount > 0) ?
+                                               Math.min(this.limitChildrenCount, array.length) : array.length;
+
+                               for (i = 0; i < l; ++i) {
+                                               pieces.push(ascii(this, array[i], processed));
+                               }
+
+                               if(l < array.length)
+                                               pieces.push("[... " + (array.length - l) + " more elements]");
+
+                               return "[" + pieces.join(", ") + "]";
+               };
+
+               ascii.object = function (object, processed, indent) {
+                               processed = processed || [];
+                               processed.push(object);
+                               indent = indent || 0;
+                               var pieces = [], properties = samsam.keys(object).sort();
+                               var length = 3;
+                               var prop, str, obj, i, k, l;
+                               l = (this.limitChildrenCount > 0) ?
+                                               Math.min(this.limitChildrenCount, properties.length) : properties.length;
+
+                               for (i = 0; i < l; ++i) {
+                                               prop = properties[i];
+                                               obj = object[prop];
+
+                                               if (isCircular(obj, processed)) {
+                                                               str = "[Circular]";
+                                               } else {
+                                                               str = ascii(this, obj, processed, indent + 2);
+                                               }
+
+                                               str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+                                               length += str.length;
+                                               pieces.push(str);
+                               }
+
+                               var cons = constructorName(this, object);
+                               var prefix = cons ? "[" + cons + "] " : "";
+                               var is = "";
+                               for (i = 0, k = indent; i < k; ++i) { is += " "; }
+
+                               if(l < properties.length)
+                                               pieces.push("[... " + (properties.length - l) + " more elements]");
+
+                               if (length + indent > 80) {
+                                               return prefix + "{\n  " + is + pieces.join(",\n  " + is) + "\n" +
+                                                               is + "}";
+                               }
+                               return prefix + "{ " + pieces.join(", ") + " }";
+               };
+
+               ascii.element = function (element) {
+                               var tagName = element.tagName.toLowerCase();
+                               var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
+
+                               for (i = 0, l = attrs.length; i < l; ++i) {
+                                               attr = attrs.item(i);
+                                               attrName = attr.nodeName.toLowerCase().replace("html:", "");
+                                               val = attr.nodeValue;
+                                               if (attrName !== "contenteditable" || val !== "inherit") {
+                                                               if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
+                                               }
+                               }
+
+                               var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+                               var content = element.innerHTML;
+
+                               if (content.length > 20) {
+                                               content = content.substr(0, 20) + "[...]";
+                               }
+
+                               var res = formatted + pairs.join(" ") + ">" + content +
+                                                               "</" + tagName + ">";
+
+                               return res.replace(/ contentEditable="inherit"/, "");
+               };
+
+               function Formatio(options) {
+                               for (var opt in options) {
+                                               this[opt] = options[opt];
+                               }
+               }
+
+               Formatio.prototype = {
+                               functionName: functionName,
+
+                               configure: function (options) {
+                                               return new Formatio(options);
+                               },
+
+                               constructorName: function (object) {
+                                               return constructorName(this, object);
+                               },
+
+                               ascii: function (object, processed, indent) {
+                                               return ascii(this, object, processed, indent);
+                               }
+               };
+
+               return Formatio.prototype;
+});
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+(function (global){
+/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
+/*global global*/
+/**
+ * @author Christian Johansen (christian@cjohansen.no) and contributors
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
+// browsers, a number.
+// see https://github.com/cjohansen/Sinon.JS/pull/436
+var timeoutResult = setTimeout(function() {}, 0);
+var addTimerReturnsObject = typeof timeoutResult === "object";
+clearTimeout(timeoutResult);
+
+var NativeDate = Date;
+var id = 1;
+
+/**
+ * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
+ * number of milliseconds. This is used to support human-readable strings passed
+ * to clock.tick()
+ */
+function parseTime(str) {
+               if (!str) {
+                               return 0;
+               }
+
+               var strings = str.split(":");
+               var l = strings.length, i = l;
+               var ms = 0, parsed;
+
+               if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+                               throw new Error("tick only understands numbers and 'h:m:s'");
+               }
+
+               while (i--) {
+                               parsed = parseInt(strings[i], 10);
+
+                               if (parsed >= 60) {
+                                               throw new Error("Invalid time " + str);
+                               }
+
+                               ms += parsed * Math.pow(60, (l - i - 1));
+               }
+
+               return ms * 1000;
+}
+
+/**
+ * Used to grok the `now` parameter to createClock.
+ */
+function getEpoch(epoch) {
+               if (!epoch) { return 0; }
+               if (typeof epoch.getTime === "function") { return epoch.getTime(); }
+               if (typeof epoch === "number") { return epoch; }
+               throw new TypeError("now should be milliseconds since UNIX epoch");
+}
+
+function inRange(from, to, timer) {
+               return timer && timer.callAt >= from && timer.callAt <= to;
+}
+
+function mirrorDateProperties(target, source) {
+               if (source.now) {
+                               target.now = function now() {
+                                               return target.clock.now;
+                               };
+               } else {
+                               delete target.now;
+               }
+
+               if (source.toSource) {
+                               target.toSource = function toSource() {
+                                               return source.toSource();
+                               };
+               } else {
+                               delete target.toSource;
+               }
+
+               target.toString = function toString() {
+                               return source.toString();
+               };
+
+               target.prototype = source.prototype;
+               target.parse = source.parse;
+               target.UTC = source.UTC;
+               target.prototype.toUTCString = source.prototype.toUTCString;
+
+               for (var prop in source) {
+                               if (source.hasOwnProperty(prop)) {
+                                               target[prop] = source[prop];
+                               }
+               }
+
+               return target;
+}
+
+function createDate() {
+               function ClockDate(year, month, date, hour, minute, second, ms) {
+                               // Defensive and verbose to avoid potential harm in passing
+                               // explicit undefined when user does not pass argument
+                               switch (arguments.length) {
+                               case 0:
+                                               return new NativeDate(ClockDate.clock.now);
+                               case 1:
+                                               return new NativeDate(year);
+                               case 2:
+                                               return new NativeDate(year, month);
+                               case 3:
+                                               return new NativeDate(year, month, date);
+                               case 4:
+                                               return new NativeDate(year, month, date, hour);
+                               case 5:
+                                               return new NativeDate(year, month, date, hour, minute);
+                               case 6:
+                                               return new NativeDate(year, month, date, hour, minute, second);
+                               default:
+                                               return new NativeDate(year, month, date, hour, minute, second, ms);
+                               }
+               }
+
+               return mirrorDateProperties(ClockDate, NativeDate);
+}
+
+function addTimer(clock, timer) {
+               if (typeof timer.func === "undefined") {
+                               throw new Error("Callback must be provided to timer calls");
+               }
+
+               if (!clock.timers) {
+                               clock.timers = {};
+               }
+
+               timer.id = id++;
+               timer.createdAt = clock.now;
+               timer.callAt = clock.now + (timer.delay || 0);
+
+               clock.timers[timer.id] = timer;
+
+               if (addTimerReturnsObject) {
+                               return {
+                                               id: timer.id,
+                                               ref: function() {},
+                                               unref: function() {}
+                               };
+               }
+               else {
+                               return timer.id;
+               }
+}
+
+function firstTimerInRange(clock, from, to) {
+               var timers = clock.timers, timer = null;
+
+               for (var id in timers) {
+                               if (!inRange(from, to, timers[id])) {
+                                               continue;
+                               }
+
+                               if (!timer || ~compareTimers(timer, timers[id])) {
+                                               timer = timers[id];
+                               }
+               }
+
+               return timer;
+}
+
+function compareTimers(a, b) {
+               // Sort first by absolute timing
+               if (a.callAt < b.callAt) {
+                               return -1;
+               }
+               if (a.callAt > b.callAt) {
+                               return 1;
+               }
+
+               // Sort next by immediate, immediate timers take precedence
+               if (a.immediate && !b.immediate) {
+                               return -1;
+               }
+               if (!a.immediate && b.immediate) {
+                               return 1;
+               }
+
+               // Sort next by creation time, earlier-created timers take precedence
+               if (a.createdAt < b.createdAt) {
+                               return -1;
+               }
+               if (a.createdAt > b.createdAt) {
+                               return 1;
+               }
+
+               // Sort next by id, lower-id timers take precedence
+               if (a.id < b.id) {
+                               return -1;
+               }
+               if (a.id > b.id) {
+                               return 1;
+               }
+
+               // As timer ids are unique, no fallback `0` is necessary
+}
+
+function callTimer(clock, timer) {
+               if (typeof timer.interval == "number") {
+                               clock.timers[timer.id].callAt += timer.interval;
+               } else {
+                               delete clock.timers[timer.id];
+               }
+
+               try {
+                               if (typeof timer.func == "function") {
+                                               timer.func.apply(null, timer.args);
+                               } else {
+                                               eval(timer.func);
+                               }
+               } catch (e) {
+                               var exception = e;
+               }
+
+               if (!clock.timers[timer.id]) {
+                               if (exception) {
+                                               throw exception;
+                               }
+                               return;
+               }
+
+               if (exception) {
+                               throw exception;
+               }
+}
+
+function uninstall(clock, target) {
+               var method;
+
+               for (var i = 0, l = clock.methods.length; i < l; i++) {
+                               method = clock.methods[i];
+
+                               if (target[method].hadOwnProperty) {
+                                               target[method] = clock["_" + method];
+                               } else {
+                                               try {
+                                                               delete target[method];
+                                               } catch (e) {}
+                               }
+               }
+
+               // Prevent multiple executions which will completely remove these props
+               clock.methods = [];
+}
+
+function hijackMethod(target, method, clock) {
+               clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
+               clock["_" + method] = target[method];
+
+               if (method == "Date") {
+                               var date = mirrorDateProperties(clock[method], target[method]);
+                               target[method] = date;
+               } else {
+                               target[method] = function () {
+                                               return clock[method].apply(clock, arguments);
+                               };
+
+                               for (var prop in clock[method]) {
+                                               if (clock[method].hasOwnProperty(prop)) {
+                                                               target[method][prop] = clock[method][prop];
+                                               }
+                               }
+               }
+
+               target[method].clock = clock;
+}
+
+var timers = {
+               setTimeout: setTimeout,
+               clearTimeout: clearTimeout,
+               setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+               clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
+               setInterval: setInterval,
+               clearInterval: clearInterval,
+               Date: Date
+};
+
+var keys = Object.keys || function (obj) {
+               var ks = [];
+               for (var key in obj) {
+                               ks.push(key);
+               }
+               return ks;
+};
+
+exports.timers = timers;
+
+var createClock = exports.createClock = function (now) {
+               var clock = {
+                               now: getEpoch(now),
+                               timeouts: {},
+                               Date: createDate()
+               };
+
+               clock.Date.clock = clock;
+
+               clock.setTimeout = function setTimeout(func, timeout) {
+                               return addTimer(clock, {
+                                               func: func,
+                                               args: Array.prototype.slice.call(arguments, 2),
+                                               delay: timeout
+                               });
+               };
+
+               clock.clearTimeout = function clearTimeout(timerId) {
+                               if (!timerId) {
+                                               // null appears to be allowed in most browsers, and appears to be
+                                               // relied upon by some libraries, like Bootstrap carousel
+                                               return;
+                               }
+                               if (!clock.timers) {
+                                               clock.timers = [];
+                               }
+                               // in Node, timerId is an object with .ref()/.unref(), and
+                               // its .id field is the actual timer id.
+                               if (typeof timerId === "object") {
+                                               timerId = timerId.id
+                               }
+                               if (timerId in clock.timers) {
+                                               delete clock.timers[timerId];
+                               }
+               };
+
+               clock.setInterval = function setInterval(func, timeout) {
+                               return addTimer(clock, {
+                                               func: func,
+                                               args: Array.prototype.slice.call(arguments, 2),
+                                               delay: timeout,
+                                               interval: timeout
+                               });
+               };
+
+               clock.clearInterval = function clearInterval(timerId) {
+                               clock.clearTimeout(timerId);
+               };
+
+               clock.setImmediate = function setImmediate(func) {
+                               return addTimer(clock, {
+                                               func: func,
+                                               args: Array.prototype.slice.call(arguments, 1),
+                                               immediate: true
+                               });
+               };
+
+               clock.clearImmediate = function clearImmediate(timerId) {
+                               clock.clearTimeout(timerId);
+               };
+
+               clock.tick = function tick(ms) {
+                               ms = typeof ms == "number" ? ms : parseTime(ms);
+                               var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
+                               var timer = firstTimerInRange(clock, tickFrom, tickTo);
+
+                               var firstException;
+                               while (timer && tickFrom <= tickTo) {
+                                               if (clock.timers[timer.id]) {
+                                                               tickFrom = clock.now = timer.callAt;
+                                                               try {
+                                                                               callTimer(clock, timer);
+                                                               } catch (e) {
+                                                                               firstException = firstException || e;
+                                                               }
+                                               }
+
+                                               timer = firstTimerInRange(clock, previous, tickTo);
+                                               previous = tickFrom;
+                               }
+
+                               clock.now = tickTo;
+
+                               if (firstException) {
+                                               throw firstException;
+                               }
+
+                               return clock.now;
+               };
+
+               clock.reset = function reset() {
+                               clock.timers = {};
+               };
+
+               return clock;
+};
+
+exports.install = function install(target, now, toFake) {
+               if (typeof target === "number") {
+                               toFake = now;
+                               now = target;
+                               target = null;
+               }
+
+               if (!target) {
+                               target = global;
+               }
+
+               var clock = createClock(now);
+
+               clock.uninstall = function () {
+                               uninstall(clock, target);
+               };
+
+               clock.methods = toFake || [];
+
+               if (clock.methods.length === 0) {
+                               clock.methods = keys(timers);
+               }
+
+               for (var i = 0, l = clock.methods.length; i < l; i++) {
+                               hijackMethod(target, clock.methods[i], clock);
+               }
+
+               return clock;
+};
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}]},{},[1])(1)
+});
+       })();
+       var define;
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+var sinon = (function () {
+"use strict";
+
+               var sinon;
+               var isNode = typeof module !== "undefined" && module.exports && typeof require === "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               sinon = module.exports = require("./sinon/util/core");
+                               require("./sinon/extend");
+                               require("./sinon/typeOf");
+                               require("./sinon/times_in_words");
+                               require("./sinon/spy");
+                               require("./sinon/call");
+                               require("./sinon/behavior");
+                               require("./sinon/stub");
+                               require("./sinon/mock");
+                               require("./sinon/collection");
+                               require("./sinon/assert");
+                               require("./sinon/sandbox");
+                               require("./sinon/test");
+                               require("./sinon/test_case");
+                               require("./sinon/match");
+                               require("./sinon/format");
+                               require("./sinon/log_error");
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+                               sinon = module.exports;
+               } else {
+                               sinon = {};
+               }
+
+               return sinon;
+}());
+
+/**
+ * @depend ../../sinon.js
+ */
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               var div = typeof document != "undefined" && document.createElement("div");
+               var hasOwn = Object.prototype.hasOwnProperty;
+
+               function isDOMNode(obj) {
+                               var success = false;
+
+                               try {
+                                               obj.appendChild(div);
+                                               success = div.parentNode == obj;
+                               } catch (e) {
+                                               return false;
+                               } finally {
+                                               try {
+                                                               obj.removeChild(div);
+                                               } catch (e) {
+                                                               // Remove failed, not much we can do about that
+                                               }
+                               }
+
+                               return success;
+               }
+
+               function isElement(obj) {
+                               return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+               }
+
+               function isFunction(obj) {
+                               return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
+               }
+
+               function isReallyNaN(val) {
+                               return typeof val === "number" && isNaN(val);
+               }
+
+               function mirrorProperties(target, source) {
+                               for (var prop in source) {
+                                               if (!hasOwn.call(target, prop)) {
+                                                               target[prop] = source[prop];
+                                               }
+                               }
+               }
+
+               function isRestorable(obj) {
+                               return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
+               }
+
+               // Cheap way to detect if we have ES5 support.
+               var hasES5Support = "keys" in Object;
+
+               function makeApi(sinon) {
+                               sinon.wrapMethod = function wrapMethod(object, property, method) {
+                                               if (!object) {
+                                                               throw new TypeError("Should wrap property of object");
+                                               }
+
+                                               if (typeof method != "function" && typeof method != "object") {
+                                                               throw new TypeError("Method wrapper should be a function or a property descriptor");
+                                               }
+
+                                               function checkWrappedMethod(wrappedMethod) {
+                                                               if (!isFunction(wrappedMethod)) {
+                                                                               error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+                                                                                                                                                               property + " as function");
+                                                               } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+                                                                               error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+                                                               } else if (wrappedMethod.calledBefore) {
+                                                                               var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
+                                                                               error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
+                                                               }
+
+                                                               if (error) {
+                                                                               if (wrappedMethod && wrappedMethod.stackTrace) {
+                                                                                               error.stack += "\n--------------\n" + wrappedMethod.stackTrace;
+                                                                               }
+                                                                               throw error;
+                                                               }
+                                               }
+
+                                               var error, wrappedMethod;
+
+                                               // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
+                                               // when using hasOwn.call on objects from other frames.
+                                               var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
+
+                                               if (hasES5Support) {
+                                                               var methodDesc = (typeof method == "function") ? {value: method} : method,
+                                                                               wrappedMethodDesc = sinon.getPropertyDescriptor(object, property),
+                                                                               i;
+
+                                                               if (!wrappedMethodDesc) {
+                                                                               error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+                                                                                                                                                               property + " as function");
+                                                               } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) {
+                                                                               error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+                                                               }
+                                                               if (error) {
+                                                                               if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) {
+                                                                                               error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace;
+                                                                               }
+                                                                               throw error;
+                                                               }
+
+                                                               var types = sinon.objectKeys(methodDesc);
+                                                               for (i = 0; i < types.length; i++) {
+                                                                               wrappedMethod = wrappedMethodDesc[types[i]];
+                                                                               checkWrappedMethod(wrappedMethod);
+                                                               }
+
+                                                               mirrorProperties(methodDesc, wrappedMethodDesc);
+                                                               for (i = 0; i < types.length; i++) {
+                                                                               mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]);
+                                                               }
+                                                               Object.defineProperty(object, property, methodDesc);
+                                               } else {
+                                                               wrappedMethod = object[property];
+                                                               checkWrappedMethod(wrappedMethod);
+                                                               object[property] = method;
+                                                               method.displayName = property;
+                                               }
+
+                                               method.displayName = property;
+
+                                               // Set up a stack trace which can be used later to find what line of
+                                               // code the original method was created on.
+                                               method.stackTrace = (new Error("Stack Trace for original")).stack;
+
+                                               method.restore = function () {
+                                                               // For prototype properties try to reset by delete first.
+                                                               // If this fails (ex: localStorage on mobile safari) then force a reset
+                                                               // via direct assignment.
+                                                               if (!owned) {
+                                                                               try {
+                                                                                               delete object[property];
+                                                                               } catch (e) {}
+                                                                               // For native code functions `delete` fails without throwing an error
+                                                                               // on Chrome < 43, PhantomJS, etc.
+                                                                               // Use strict equality comparison to check failures then force a reset
+                                                                               // via direct assignment.
+                                                                               if (object[property] === method) {
+                                                                                               object[property] = wrappedMethod;
+                                                                               }
+                                                               } else if (hasES5Support) {
+                                                                               Object.defineProperty(object, property, wrappedMethodDesc);
+                                                               }
+
+                                                               if (!hasES5Support && object[property] === method) {
+                                                                               object[property] = wrappedMethod;
+                                                               }
+                                               };
+
+                                               method.restore.sinon = true;
+
+                                               if (!hasES5Support) {
+                                                               mirrorProperties(method, wrappedMethod);
+                                               }
+
+                                               return method;
+                               };
+
+                               sinon.create = function create(proto) {
+                                               var F = function () {};
+                                               F.prototype = proto;
+                                               return new F();
+                               };
+
+                               sinon.deepEqual = function deepEqual(a, b) {
+                                               if (sinon.match && sinon.match.isMatcher(a)) {
+                                                               return a.test(b);
+                                               }
+
+                                               if (typeof a != "object" || typeof b != "object") {
+                                                               if (isReallyNaN(a) && isReallyNaN(b)) {
+                                                                               return true;
+                                                               } else {
+                                                                               return a === b;
+                                                               }
+                                               }
+
+                                               if (isElement(a) || isElement(b)) {
+                                                               return a === b;
+                                               }
+
+                                               if (a === b) {
+                                                               return true;
+                                               }
+
+                                               if ((a === null && b !== null) || (a !== null && b === null)) {
+                                                               return false;
+                                               }
+
+                                               if (a instanceof RegExp && b instanceof RegExp) {
+                                                               return (a.source === b.source) && (a.global === b.global) &&
+                                                                               (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
+                                               }
+
+                                               var aString = Object.prototype.toString.call(a);
+                                               if (aString != Object.prototype.toString.call(b)) {
+                                                               return false;
+                                               }
+
+                                               if (aString == "[object Date]") {
+                                                               return a.valueOf() === b.valueOf();
+                                               }
+
+                                               var prop, aLength = 0, bLength = 0;
+
+                                               if (aString == "[object Array]" && a.length !== b.length) {
+                                                               return false;
+                                               }
+
+                                               for (prop in a) {
+                                                               aLength += 1;
+
+                                                               if (!(prop in b)) {
+                                                                               return false;
+                                                               }
+
+                                                               if (!deepEqual(a[prop], b[prop])) {
+                                                                               return false;
+                                                               }
+                                               }
+
+                                               for (prop in b) {
+                                                               bLength += 1;
+                                               }
+
+                                               return aLength == bLength;
+                               };
+
+                               sinon.functionName = function functionName(func) {
+                                               var name = func.displayName || func.name;
+
+                                               // Use function decomposition as a last resort to get function
+                                               // name. Does not rely on function decomposition to work - if it
+                                               // doesn't debugging will be slightly less informative
+                                               // (i.e. toString will say 'spy' rather than 'myFunc').
+                                               if (!name) {
+                                                               var matches = func.toString().match(/function ([^\s\(]+)/);
+                                                               name = matches && matches[1];
+                                               }
+
+                                               return name;
+                               };
+
+                               sinon.functionToString = function toString() {
+                                               if (this.getCall && this.callCount) {
+                                                               var thisValue, prop, i = this.callCount;
+
+                                                               while (i--) {
+                                                                               thisValue = this.getCall(i).thisValue;
+
+                                                                               for (prop in thisValue) {
+                                                                                               if (thisValue[prop] === this) {
+                                                                                                               return prop;
+                                                                                               }
+                                                                               }
+                                                               }
+                                               }
+
+                                               return this.displayName || "sinon fake";
+                               };
+
+                               sinon.objectKeys = function objectKeys(obj) {
+                                               if (obj !== Object(obj)) {
+                                                               throw new TypeError("sinon.objectKeys called on a non-object");
+                                               }
+
+                                               var keys = [];
+                                               var key;
+                                               for (key in obj) {
+                                                               if (hasOwn.call(obj, key)) {
+                                                                               keys.push(key);
+                                                               }
+                                               }
+
+                                               return keys;
+                               };
+
+                               sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) {
+                                               var proto = object, descriptor;
+                                               while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) {
+                                                               proto = Object.getPrototypeOf(proto);
+                                               }
+                                               return descriptor;
+                               }
+
+                               sinon.getConfig = function (custom) {
+                                               var config = {};
+                                               custom = custom || {};
+                                               var defaults = sinon.defaultConfig;
+
+                                               for (var prop in defaults) {
+                                                               if (defaults.hasOwnProperty(prop)) {
+                                                                               config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
+                                                               }
+                                               }
+
+                                               return config;
+                               };
+
+                               sinon.defaultConfig = {
+                                               injectIntoThis: true,
+                                               injectInto: null,
+                                               properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+                                               useFakeTimers: true,
+                                               useFakeServer: true
+                               };
+
+                               sinon.timesInWords = function timesInWords(count) {
+                                               return count == 1 && "once" ||
+                                                               count == 2 && "twice" ||
+                                                               count == 3 && "thrice" ||
+                                                               (count || 0) + " times";
+                               };
+
+                               sinon.calledInOrder = function (spies) {
+                                               for (var i = 1, l = spies.length; i < l; i++) {
+                                                               if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
+                                                                               return false;
+                                                               }
+                                               }
+
+                                               return true;
+                               };
+
+                               sinon.orderByFirstCall = function (spies) {
+                                               return spies.sort(function (a, b) {
+                                                               // uuid, won't ever be equal
+                                                               var aCall = a.getCall(0);
+                                                               var bCall = b.getCall(0);
+                                                               var aId = aCall && aCall.callId || -1;
+                                                               var bId = bCall && bCall.callId || -1;
+
+                                                               return aId < bId ? -1 : 1;
+                                               });
+                               };
+
+                               sinon.createStubInstance = function (constructor) {
+                                               if (typeof constructor !== "function") {
+                                                               throw new TypeError("The constructor should be a function.");
+                                               }
+                                               return sinon.stub(sinon.create(constructor.prototype));
+                               };
+
+                               sinon.restore = function (object) {
+                                               if (object !== null && typeof object === "object") {
+                                                               for (var prop in object) {
+                                                                               if (isRestorable(object[prop])) {
+                                                                                               object[prop].restore();
+                                                                               }
+                                                               }
+                                               } else if (isRestorable(object)) {
+                                                               object.restore();
+                                               }
+                               };
+
+                               return sinon;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports) {
+                               makeApi(exports);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+
+(function (sinon) {
+               function makeApi(sinon) {
+
+                               // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
+                               var hasDontEnumBug = (function () {
+                                               var obj = {
+                                                               constructor: function () {
+                                                                               return "0";
+                                                               },
+                                                               toString: function () {
+                                                                               return "1";
+                                                               },
+                                                               valueOf: function () {
+                                                                               return "2";
+                                                               },
+                                                               toLocaleString: function () {
+                                                                               return "3";
+                                                               },
+                                                               prototype: function () {
+                                                                               return "4";
+                                                               },
+                                                               isPrototypeOf: function () {
+                                                                               return "5";
+                                                               },
+                                                               propertyIsEnumerable: function () {
+                                                                               return "6";
+                                                               },
+                                                               hasOwnProperty: function () {
+                                                                               return "7";
+                                                               },
+                                                               length: function () {
+                                                                               return "8";
+                                                               },
+                                                               unique: function () {
+                                                                               return "9"
+                                                               }
+                                               };
+
+                                               var result = [];
+                                               for (var prop in obj) {
+                                                               result.push(obj[prop]());
+                                               }
+                                               return result.join("") !== "0123456789";
+                               })();
+
+                               /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will
+                                *         override properties in previous sources.
+                                *
+                                * target - The Object to extend
+                                * sources - Objects to copy properties from.
+                                *
+                                * Returns the extended target
+                                */
+                               function extend(target /*, sources */) {
+                                               var sources = Array.prototype.slice.call(arguments, 1),
+                                                               source, i, prop;
+
+                                               for (i = 0; i < sources.length; i++) {
+                                                               source = sources[i];
+
+                                                               for (prop in source) {
+                                                                               if (source.hasOwnProperty(prop)) {
+                                                                                               target[prop] = source[prop];
+                                                                               }
+                                                               }
+
+                                                               // Make sure we copy (own) toString method even when in JScript with DontEnum bug
+                                                               // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
+                                                               if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) {
+                                                                               target.toString = source.toString;
+                                                               }
+                                               }
+
+                                               return target;
+                               };
+
+                               sinon.extend = extend;
+                               return sinon.extend;
+               }
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               module.exports = makeApi(sinon);
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+
+(function (sinon) {
+               function makeApi(sinon) {
+
+                               function timesInWords(count) {
+                                               switch (count) {
+                                                               case 1:
+                                                                               return "once";
+                                                               case 2:
+                                                                               return "twice";
+                                                               case 3:
+                                                                               return "thrice";
+                                                               default:
+                                                                               return (count || 0) + " times";
+                                               }
+                               }
+
+                               sinon.timesInWords = timesInWords;
+                               return sinon.timesInWords;
+               }
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               module.exports = makeApi(sinon);
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+/**
+ * Format functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+(function (sinon, formatio) {
+               function makeApi(sinon) {
+                               function typeOf(value) {
+                                               if (value === null) {
+                                                               return "null";
+                                               } else if (value === undefined) {
+                                                               return "undefined";
+                                               }
+                                               var string = Object.prototype.toString.call(value);
+                                               return string.substring(8, string.length - 1).toLowerCase();
+                               };
+
+                               sinon.typeOf = typeOf;
+                               return sinon.typeOf;
+               }
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               module.exports = makeApi(sinon);
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(
+               (typeof sinon == "object" && sinon || null),
+               (typeof formatio == "object" && formatio)
+));
+
+/**
+ * @depend util/core.js
+ * @depend typeOf.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Match functions
+ *
+ * @author Maximilian Antoni (mail@maxantoni.de)
+ * @license BSD
+ *
+ * Copyright (c) 2012 Maximilian Antoni
+ */
+
+(function (sinon) {
+               function makeApi(sinon) {
+                               function assertType(value, type, name) {
+                                               var actual = sinon.typeOf(value);
+                                               if (actual !== type) {
+                                                               throw new TypeError("Expected type of " + name + " to be " +
+                                                                               type + ", but was " + actual);
+                                               }
+                               }
+
+                               var matcher = {
+                                               toString: function () {
+                                                               return this.message;
+                                               }
+                               };
+
+                               function isMatcher(object) {
+                                               return matcher.isPrototypeOf(object);
+                               }
+
+                               function matchObject(expectation, actual) {
+                                               if (actual === null || actual === undefined) {
+                                                               return false;
+                                               }
+                                               for (var key in expectation) {
+                                                               if (expectation.hasOwnProperty(key)) {
+                                                                               var exp = expectation[key];
+                                                                               var act = actual[key];
+                                                                               if (match.isMatcher(exp)) {
+                                                                                               if (!exp.test(act)) {
+                                                                                                               return false;
+                                                                                               }
+                                                                               } else if (sinon.typeOf(exp) === "object") {
+                                                                                               if (!matchObject(exp, act)) {
+                                                                                                               return false;
+                                                                                               }
+                                                                               } else if (!sinon.deepEqual(exp, act)) {
+                                                                                               return false;
+                                                                               }
+                                                               }
+                                               }
+                                               return true;
+                               }
+
+                               matcher.or = function (m2) {
+                                               if (!arguments.length) {
+                                                               throw new TypeError("Matcher expected");
+                                               } else if (!isMatcher(m2)) {
+                                                               m2 = match(m2);
+                                               }
+                                               var m1 = this;
+                                               var or = sinon.create(matcher);
+                                               or.test = function (actual) {
+                                                               return m1.test(actual) || m2.test(actual);
+                                               };
+                                               or.message = m1.message + ".or(" + m2.message + ")";
+                                               return or;
+                               };
+
+                               matcher.and = function (m2) {
+                                               if (!arguments.length) {
+                                                               throw new TypeError("Matcher expected");
+                                               } else if (!isMatcher(m2)) {
+                                                               m2 = match(m2);
+                                               }
+                                               var m1 = this;
+                                               var and = sinon.create(matcher);
+                                               and.test = function (actual) {
+                                                               return m1.test(actual) && m2.test(actual);
+                                               };
+                                               and.message = m1.message + ".and(" + m2.message + ")";
+                                               return and;
+                               };
+
+                               var match = function (expectation, message) {
+                                               var m = sinon.create(matcher);
+                                               var type = sinon.typeOf(expectation);
+                                               switch (type) {
+                                               case "object":
+                                                               if (typeof expectation.test === "function") {
+                                                                               m.test = function (actual) {
+                                                                                               return expectation.test(actual) === true;
+                                                                               };
+                                                                               m.message = "match(" + sinon.functionName(expectation.test) + ")";
+                                                                               return m;
+                                                               }
+                                                               var str = [];
+                                                               for (var key in expectation) {
+                                                                               if (expectation.hasOwnProperty(key)) {
+                                                                                               str.push(key + ": " + expectation[key]);
+                                                                               }
+                                                               }
+                                                               m.test = function (actual) {
+                                                                               return matchObject(expectation, actual);
+                                                               };
+                                                               m.message = "match(" + str.join(", ") + ")";
+                                                               break;
+                                               case "number":
+                                                               m.test = function (actual) {
+                                                                               return expectation == actual;
+                                                               };
+                                                               break;
+                                               case "string":
+                                                               m.test = function (actual) {
+                                                                               if (typeof actual !== "string") {
+                                                                                               return false;
+                                                                               }
+                                                                               return actual.indexOf(expectation) !== -1;
+                                                               };
+                                                               m.message = "match(\"" + expectation + "\")";
+                                                               break;
+                                               case "regexp":
+                                                               m.test = function (actual) {
+                                                                               if (typeof actual !== "string") {
+                                                                                               return false;
+                                                                               }
+                                                                               return expectation.test(actual);
+                                                               };
+                                                               break;
+                                               case "function":
+                                                               m.test = expectation;
+                                                               if (message) {
+                                                                               m.message = message;
+                                                               } else {
+                                                                               m.message = "match(" + sinon.functionName(expectation) + ")";
+                                                               }
+                                                               break;
+                                               default:
+                                                               m.test = function (actual) {
+                                                                               return sinon.deepEqual(expectation, actual);
+                                                               };
+                                               }
+                                               if (!m.message) {
+                                                               m.message = "match(" + expectation + ")";
+                                               }
+                                               return m;
+                               };
+
+                               match.isMatcher = isMatcher;
+
+                               match.any = match(function () {
+                                               return true;
+                               }, "any");
+
+                               match.defined = match(function (actual) {
+                                               return actual !== null && actual !== undefined;
+                               }, "defined");
+
+                               match.truthy = match(function (actual) {
+                                               return !!actual;
+                               }, "truthy");
+
+                               match.falsy = match(function (actual) {
+                                               return !actual;
+                               }, "falsy");
+
+                               match.same = function (expectation) {
+                                               return match(function (actual) {
+                                                               return expectation === actual;
+                                               }, "same(" + expectation + ")");
+                               };
+
+                               match.typeOf = function (type) {
+                                               assertType(type, "string", "type");
+                                               return match(function (actual) {
+                                                               return sinon.typeOf(actual) === type;
+                                               }, "typeOf(\"" + type + "\")");
+                               };
+
+                               match.instanceOf = function (type) {
+                                               assertType(type, "function", "type");
+                                               return match(function (actual) {
+                                                               return actual instanceof type;
+                                               }, "instanceOf(" + sinon.functionName(type) + ")");
+                               };
+
+                               function createPropertyMatcher(propertyTest, messagePrefix) {
+                                               return function (property, value) {
+                                                               assertType(property, "string", "property");
+                                                               var onlyProperty = arguments.length === 1;
+                                                               var message = messagePrefix + "(\"" + property + "\"";
+                                                               if (!onlyProperty) {
+                                                                               message += ", " + value;
+                                                               }
+                                                               message += ")";
+                                                               return match(function (actual) {
+                                                                               if (actual === undefined || actual === null ||
+                                                                                                               !propertyTest(actual, property)) {
+                                                                                               return false;
+                                                                               }
+                                                                               return onlyProperty || sinon.deepEqual(value, actual[property]);
+                                                               }, message);
+                                               };
+                               }
+
+                               match.has = createPropertyMatcher(function (actual, property) {
+                                               if (typeof actual === "object") {
+                                                               return property in actual;
+                                               }
+                                               return actual[property] !== undefined;
+                               }, "has");
+
+                               match.hasOwn = createPropertyMatcher(function (actual, property) {
+                                               return actual.hasOwnProperty(property);
+                               }, "hasOwn");
+
+                               match.bool = match.typeOf("boolean");
+                               match.number = match.typeOf("number");
+                               match.string = match.typeOf("string");
+                               match.object = match.typeOf("object");
+                               match.func = match.typeOf("function");
+                               match.array = match.typeOf("array");
+                               match.regexp = match.typeOf("regexp");
+                               match.date = match.typeOf("date");
+
+                               sinon.match = match;
+                               return match;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./typeOf");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+/**
+ * Format functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+(function (sinon, formatio) {
+               function makeApi(sinon) {
+                               function valueFormatter(value) {
+                                               return "" + value;
+                               }
+
+                               function getFormatioFormatter() {
+                                               var formatter = formatio.configure({
+                                                                               quoteStrings: false,
+                                                                               limitChildrenCount: 250
+                                                               });
+
+                                               function format() {
+                                                               return formatter.ascii.apply(formatter, arguments);
+                                               };
+
+                                               return format;
+                               }
+
+                               function getNodeFormatter(value) {
+                                               function format(value) {
+                                                               return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
+                                               };
+
+                                               try {
+                                                               var util = require("util");
+                                               } catch (e) {
+                                                               /* Node, but no util module - would be very old, but better safe than sorry */
+                                               }
+
+                                               return util ? format : valueFormatter;
+                               }
+
+                               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function",
+                                               formatter;
+
+                               if (isNode) {
+                                               try {
+                                                               formatio = require("formatio");
+                                               } catch (e) {}
+                               }
+
+                               if (formatio) {
+                                               formatter = getFormatioFormatter()
+                               } else if (isNode) {
+                                               formatter = getNodeFormatter();
+                               } else {
+                                               formatter = valueFormatter;
+                               }
+
+                               sinon.format = formatter;
+                               return sinon.format;
+               }
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               module.exports = makeApi(sinon);
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(
+               (typeof sinon == "object" && sinon || null),
+               (typeof formatio == "object" && formatio)
+));
+
+/**
+       * @depend util/core.js
+       * @depend match.js
+       * @depend format.js
+       */
+/**
+       * Spy calls
+       *
+       * @author Christian Johansen (christian@cjohansen.no)
+       * @author Maximilian Antoni (mail@maxantoni.de)
+       * @license BSD
+       *
+       * Copyright (c) 2010-2013 Christian Johansen
+       * Copyright (c) 2013 Maximilian Antoni
+       */
+
+(function (sinon) {
+               function makeApi(sinon) {
+                               function throwYieldError(proxy, text, args) {
+                                               var msg = sinon.functionName(proxy) + text;
+                                               if (args.length) {
+                                                               msg += " Received [" + slice.call(args).join(", ") + "]";
+                                               }
+                                               throw new Error(msg);
+                               }
+
+                               var slice = Array.prototype.slice;
+
+                               var callProto = {
+                                               calledOn: function calledOn(thisValue) {
+                                                               if (sinon.match && sinon.match.isMatcher(thisValue)) {
+                                                                               return thisValue.test(this.thisValue);
+                                                               }
+                                                               return this.thisValue === thisValue;
+                                               },
+
+                                               calledWith: function calledWith() {
+                                                               var l = arguments.length;
+                                                               if (l > this.args.length) {
+                                                                               return false;
+                                                               }
+                                                               for (var i = 0; i < l; i += 1) {
+                                                                               if (!sinon.deepEqual(arguments[i], this.args[i])) {
+                                                                                               return false;
+                                                                               }
+                                                               }
+
+                                                               return true;
+                                               },
+
+                                               calledWithMatch: function calledWithMatch() {
+                                                               var l = arguments.length;
+                                                               if (l > this.args.length) {
+                                                                               return false;
+                                                               }
+                                                               for (var i = 0; i < l; i += 1) {
+                                                                               var actual = this.args[i];
+                                                                               var expectation = arguments[i];
+                                                                               if (!sinon.match || !sinon.match(expectation).test(actual)) {
+                                                                                               return false;
+                                                                               }
+                                                               }
+                                                               return true;
+                                               },
+
+                                               calledWithExactly: function calledWithExactly() {
+                                                               return arguments.length == this.args.length &&
+                                                                               this.calledWith.apply(this, arguments);
+                                               },
+
+                                               notCalledWith: function notCalledWith() {
+                                                               return !this.calledWith.apply(this, arguments);
+                                               },
+
+                                               notCalledWithMatch: function notCalledWithMatch() {
+                                                               return !this.calledWithMatch.apply(this, arguments);
+                                               },
+
+                                               returned: function returned(value) {
+                                                               return sinon.deepEqual(value, this.returnValue);
+                                               },
+
+                                               threw: function threw(error) {
+                                                               if (typeof error === "undefined" || !this.exception) {
+                                                                               return !!this.exception;
+                                                               }
+
+                                                               return this.exception === error || this.exception.name === error;
+                                               },
+
+                                               calledWithNew: function calledWithNew() {
+                                                               return this.proxy.prototype && this.thisValue instanceof this.proxy;
+                                               },
+
+                                               calledBefore: function (other) {
+                                                               return this.callId < other.callId;
+                                               },
+
+                                               calledAfter: function (other) {
+                                                               return this.callId > other.callId;
+                                               },
+
+                                               callArg: function (pos) {
+                                                               this.args[pos]();
+                                               },
+
+                                               callArgOn: function (pos, thisValue) {
+                                                               this.args[pos].apply(thisValue);
+                                               },
+
+                                               callArgWith: function (pos) {
+                                                               this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
+                                               },
+
+                                               callArgOnWith: function (pos, thisValue) {
+                                                               var args = slice.call(arguments, 2);
+                                                               this.args[pos].apply(thisValue, args);
+                                               },
+
+                                               yield: function () {
+                                                               this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
+                                               },
+
+                                               yieldOn: function (thisValue) {
+                                                               var args = this.args;
+                                                               for (var i = 0, l = args.length; i < l; ++i) {
+                                                                               if (typeof args[i] === "function") {
+                                                                                               args[i].apply(thisValue, slice.call(arguments, 1));
+                                                                                               return;
+                                                                               }
+                                                               }
+                                                               throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+                                               },
+
+                                               yieldTo: function (prop) {
+                                                               this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
+                                               },
+
+                                               yieldToOn: function (prop, thisValue) {
+                                                               var args = this.args;
+                                                               for (var i = 0, l = args.length; i < l; ++i) {
+                                                                               if (args[i] && typeof args[i][prop] === "function") {
+                                                                                               args[i][prop].apply(thisValue, slice.call(arguments, 2));
+                                                                                               return;
+                                                                               }
+                                                               }
+                                                               throwYieldError(this.proxy, " cannot yield to '" + prop +
+                                                                               "' since no callback was passed.", args);
+                                               },
+
+                                               toString: function () {
+                                                               var callStr = this.proxy.toString() + "(";
+                                                               var args = [];
+
+                                                               for (var i = 0, l = this.args.length; i < l; ++i) {
+                                                                               args.push(sinon.format(this.args[i]));
+                                                               }
+
+                                                               callStr = callStr + args.join(", ") + ")";
+
+                                                               if (typeof this.returnValue != "undefined") {
+                                                                               callStr += " => " + sinon.format(this.returnValue);
+                                                               }
+
+                                                               if (this.exception) {
+                                                                               callStr += " !" + this.exception.name;
+
+                                                                               if (this.exception.message) {
+                                                                                               callStr += "(" + this.exception.message + ")";
+                                                                               }
+                                                               }
+
+                                                               return callStr;
+                                               }
+                               };
+
+                               callProto.invokeCallback = callProto.yield;
+
+                               function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
+                                               if (typeof id !== "number") {
+                                                               throw new TypeError("Call id is not a number");
+                                               }
+                                               var proxyCall = sinon.create(callProto);
+                                               proxyCall.proxy = spy;
+                                               proxyCall.thisValue = thisValue;
+                                               proxyCall.args = args;
+                                               proxyCall.returnValue = returnValue;
+                                               proxyCall.exception = exception;
+                                               proxyCall.callId = id;
+
+                                               return proxyCall;
+                               }
+                               createSpyCall.toString = callProto.toString; // used by mocks
+
+                               sinon.spyCall = createSpyCall;
+                               return createSpyCall;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./match");
+                               require("./format");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+       * @depend times_in_words.js
+       * @depend util/core.js
+       * @depend extend.js
+       * @depend call.js
+       * @depend format.js
+       */
+/**
+       * Spy functions
+       *
+       * @author Christian Johansen (christian@cjohansen.no)
+       * @license BSD
+       *
+       * Copyright (c) 2010-2013 Christian Johansen
+       */
+
+(function (sinon) {
+
+               function makeApi(sinon) {
+                               var push = Array.prototype.push;
+                               var slice = Array.prototype.slice;
+                               var callId = 0;
+
+                               function spy(object, property, types) {
+                                               if (!property && typeof object == "function") {
+                                                               return spy.create(object);
+                                               }
+
+                                               if (!object && !property) {
+                                                               return spy.create(function () { });
+                                               }
+
+                                               if (types) {
+                                                               var methodDesc = sinon.getPropertyDescriptor(object, property);
+                                                               for (var i = 0; i < types.length; i++) {
+                                                                               methodDesc[types[i]] = spy.create(methodDesc[types[i]]);
+                                                               }
+                                                               return sinon.wrapMethod(object, property, methodDesc);
+                                               } else {
+                                                               var method = object[property];
+                                                               return sinon.wrapMethod(object, property, spy.create(method));
+                                               }
+                               }
+
+                               function matchingFake(fakes, args, strict) {
+                                               if (!fakes) {
+                                                               return;
+                                               }
+
+                                               for (var i = 0, l = fakes.length; i < l; i++) {
+                                                               if (fakes[i].matches(args, strict)) {
+                                                                               return fakes[i];
+                                                               }
+                                               }
+                               }
+
+                               function incrementCallCount() {
+                                               this.called = true;
+                                               this.callCount += 1;
+                                               this.notCalled = false;
+                                               this.calledOnce = this.callCount == 1;
+                                               this.calledTwice = this.callCount == 2;
+                                               this.calledThrice = this.callCount == 3;
+                               }
+
+                               function createCallProperties() {
+                                               this.firstCall = this.getCall(0);
+                                               this.secondCall = this.getCall(1);
+                                               this.thirdCall = this.getCall(2);
+                                               this.lastCall = this.getCall(this.callCount - 1);
+                               }
+
+                               var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
+                               function createProxy(func, proxyLength) {
+                                               // Retain the function length:
+                                               var p;
+                                               if (proxyLength) {
+                                                               eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) +
+                                                                               ") { return p.invoke(func, this, slice.call(arguments)); });");
+                                               } else {
+                                                               p = function proxy() {
+                                                                               return p.invoke(func, this, slice.call(arguments));
+                                                               };
+                                               }
+                                               return p;
+                               }
+
+                               var uuid = 0;
+
+                               // Public API
+                               var spyApi = {
+                                               reset: function () {
+                                                               if (this.invoking) {
+                                                                               var err = new Error("Cannot reset Sinon function while invoking it. " +
+                                                                                                                                                               "Move the call to .reset outside of the callback.");
+                                                                               err.name = "InvalidResetException";
+                                                                               throw err;
+                                                               }
+
+                                                               this.called = false;
+                                                               this.notCalled = true;
+                                                               this.calledOnce = false;
+                                                               this.calledTwice = false;
+                                                               this.calledThrice = false;
+                                                               this.callCount = 0;
+                                                               this.firstCall = null;
+                                                               this.secondCall = null;
+                                                               this.thirdCall = null;
+                                                               this.lastCall = null;
+                                                               this.args = [];
+                                                               this.returnValues = [];
+                                                               this.thisValues = [];
+                                                               this.exceptions = [];
+                                                               this.callIds = [];
+                                                               if (this.fakes) {
+                                                                               for (var i = 0; i < this.fakes.length; i++) {
+                                                                                               this.fakes[i].reset();
+                                                                               }
+                                                               }
+
+                                                               return this;
+                                               },
+
+                                               create: function create(func, spyLength) {
+                                                               var name;
+
+                                                               if (typeof func != "function") {
+                                                                               func = function () { };
+                                                               } else {
+                                                                               name = sinon.functionName(func);
+                                                               }
+
+                                                               if (!spyLength) {
+                                                                               spyLength = func.length;
+                                                               }
+
+                                                               var proxy = createProxy(func, spyLength);
+
+                                                               sinon.extend(proxy, spy);
+                                                               delete proxy.create;
+                                                               sinon.extend(proxy, func);
+
+                                                               proxy.reset();
+                                                               proxy.prototype = func.prototype;
+                                                               proxy.displayName = name || "spy";
+                                                               proxy.toString = sinon.functionToString;
+                                                               proxy.instantiateFake = sinon.spy.create;
+                                                               proxy.id = "spy#" + uuid++;
+
+                                                               return proxy;
+                                               },
+
+                                               invoke: function invoke(func, thisValue, args) {
+                                                               var matching = matchingFake(this.fakes, args);
+                                                               var exception, returnValue;
+
+                                                               incrementCallCount.call(this);
+                                                               push.call(this.thisValues, thisValue);
+                                                               push.call(this.args, args);
+                                                               push.call(this.callIds, callId++);
+
+                                                               // Make call properties available from within the spied function:
+                                                               createCallProperties.call(this);
+
+                                                               try {
+                                                                               this.invoking = true;
+
+                                                                               if (matching) {
+                                                                                               returnValue = matching.invoke(func, thisValue, args);
+                                                                               } else {
+                                                                                               returnValue = (this.func || func).apply(thisValue, args);
+                                                                               }
+
+                                                                               var thisCall = this.getCall(this.callCount - 1);
+                                                                               if (thisCall.calledWithNew() && typeof returnValue !== "object") {
+                                                                                               returnValue = thisValue;
+                                                                               }
+                                                               } catch (e) {
+                                                                               exception = e;
+                                                               } finally {
+                                                                               delete this.invoking;
+                                                               }
+
+                                                               push.call(this.exceptions, exception);
+                                                               push.call(this.returnValues, returnValue);
+
+                                                               // Make return value and exception available in the calls:
+                                                               createCallProperties.call(this);
+
+                                                               if (exception !== undefined) {
+                                                                               throw exception;
+                                                               }
+
+                                                               return returnValue;
+                                               },
+
+                                               named: function named(name) {
+                                                               this.displayName = name;
+                                                               return this;
+                                               },
+
+                                               getCall: function getCall(i) {
+                                                               if (i < 0 || i >= this.callCount) {
+                                                                               return null;
+                                                               }
+
+                                                               return sinon.spyCall(this, this.thisValues[i], this.args[i],
+                                                                                                                                                               this.returnValues[i], this.exceptions[i],
+                                                                                                                                                               this.callIds[i]);
+                                               },
+
+                                               getCalls: function () {
+                                                               var calls = [];
+                                                               var i;
+
+                                                               for (i = 0; i < this.callCount; i++) {
+                                                                               calls.push(this.getCall(i));
+                                                               }
+
+                                                               return calls;
+                                               },
+
+                                               calledBefore: function calledBefore(spyFn) {
+                                                               if (!this.called) {
+                                                                               return false;
+                                                               }
+
+                                                               if (!spyFn.called) {
+                                                                               return true;
+                                                               }
+
+                                                               return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+                                               },
+
+                                               calledAfter: function calledAfter(spyFn) {
+                                                               if (!this.called || !spyFn.called) {
+                                                                               return false;
+                                                               }
+
+                                                               return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+                                               },
+
+                                               withArgs: function () {
+                                                               var args = slice.call(arguments);
+
+                                                               if (this.fakes) {
+                                                                               var match = matchingFake(this.fakes, args, true);
+
+                                                                               if (match) {
+                                                                                               return match;
+                                                                               }
+                                                               } else {
+                                                                               this.fakes = [];
+                                                               }
+
+                                                               var original = this;
+                                                               var fake = this.instantiateFake();
+                                                               fake.matchingAguments = args;
+                                                               fake.parent = this;
+                                                               push.call(this.fakes, fake);
+
+                                                               fake.withArgs = function () {
+                                                                               return original.withArgs.apply(original, arguments);
+                                                               };
+
+                                                               for (var i = 0; i < this.args.length; i++) {
+                                                                               if (fake.matches(this.args[i])) {
+                                                                                               incrementCallCount.call(fake);
+                                                                                               push.call(fake.thisValues, this.thisValues[i]);
+                                                                                               push.call(fake.args, this.args[i]);
+                                                                                               push.call(fake.returnValues, this.returnValues[i]);
+                                                                                               push.call(fake.exceptions, this.exceptions[i]);
+                                                                                               push.call(fake.callIds, this.callIds[i]);
+                                                                               }
+                                                               }
+                                                               createCallProperties.call(fake);
+
+                                                               return fake;
+                                               },
+
+                                               matches: function (args, strict) {
+                                                               var margs = this.matchingAguments;
+
+                                                               if (margs.length <= args.length &&
+                                                                               sinon.deepEqual(margs, args.slice(0, margs.length))) {
+                                                                               return !strict || margs.length == args.length;
+                                                               }
+                                               },
+
+                                               printf: function (format) {
+                                                               var spy = this;
+                                                               var args = slice.call(arguments, 1);
+                                                               var formatter;
+
+                                                               return (format || "").replace(/%(.)/g, function (match, specifyer) {
+                                                                               formatter = spyApi.formatters[specifyer];
+
+                                                                               if (typeof formatter == "function") {
+                                                                                               return formatter.call(null, spy, args);
+                                                                               } else if (!isNaN(parseInt(specifyer, 10))) {
+                                                                                               return sinon.format(args[specifyer - 1]);
+                                                                               }
+
+                                                                               return "%" + specifyer;
+                                                               });
+                                               }
+                               };
+
+                               function delegateToCalls(method, matchAny, actual, notCalled) {
+                                               spyApi[method] = function () {
+                                                               if (!this.called) {
+                                                                               if (notCalled) {
+                                                                                               return notCalled.apply(this, arguments);
+                                                                               }
+                                                                               return false;
+                                                               }
+
+                                                               var currentCall;
+                                                               var matches = 0;
+
+                                                               for (var i = 0, l = this.callCount; i < l; i += 1) {
+                                                                               currentCall = this.getCall(i);
+
+                                                                               if (currentCall[actual || method].apply(currentCall, arguments)) {
+                                                                                               matches += 1;
+
+                                                                                               if (matchAny) {
+                                                                                                               return true;
+                                                                                               }
+                                                                               }
+                                                               }
+
+                                                               return matches === this.callCount;
+                                               };
+                               }
+
+                               delegateToCalls("calledOn", true);
+                               delegateToCalls("alwaysCalledOn", false, "calledOn");
+                               delegateToCalls("calledWith", true);
+                               delegateToCalls("calledWithMatch", true);
+                               delegateToCalls("alwaysCalledWith", false, "calledWith");
+                               delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
+                               delegateToCalls("calledWithExactly", true);
+                               delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
+                               delegateToCalls("neverCalledWith", false, "notCalledWith",
+                                               function () { return true; });
+                               delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
+                                               function () { return true; });
+                               delegateToCalls("threw", true);
+                               delegateToCalls("alwaysThrew", false, "threw");
+                               delegateToCalls("returned", true);
+                               delegateToCalls("alwaysReturned", false, "returned");
+                               delegateToCalls("calledWithNew", true);
+                               delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
+                               delegateToCalls("callArg", false, "callArgWith", function () {
+                                               throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+                               });
+                               spyApi.callArgWith = spyApi.callArg;
+                               delegateToCalls("callArgOn", false, "callArgOnWith", function () {
+                                               throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+                               });
+                               spyApi.callArgOnWith = spyApi.callArgOn;
+                               delegateToCalls("yield", false, "yield", function () {
+                                               throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+                               });
+                               // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+                               spyApi.invokeCallback = spyApi.yield;
+                               delegateToCalls("yieldOn", false, "yieldOn", function () {
+                                               throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+                               });
+                               delegateToCalls("yieldTo", false, "yieldTo", function (property) {
+                                               throw new Error(this.toString() + " cannot yield to '" + property +
+                                                               "' since it was not yet invoked.");
+                               });
+                               delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
+                                               throw new Error(this.toString() + " cannot yield to '" + property +
+                                                               "' since it was not yet invoked.");
+                               });
+
+                               spyApi.formatters = {
+                                               c: function (spy) {
+                                                               return sinon.timesInWords(spy.callCount);
+                                               },
+
+                                               n: function (spy) {
+                                                               return spy.toString();
+                                               },
+
+                                               C: function (spy) {
+                                                               var calls = [];
+
+                                                               for (var i = 0, l = spy.callCount; i < l; ++i) {
+                                                                               var stringifiedCall = "    " + spy.getCall(i).toString();
+                                                                               if (/\n/.test(calls[i - 1])) {
+                                                                                               stringifiedCall = "\n" + stringifiedCall;
+                                                                               }
+                                                                               push.call(calls, stringifiedCall);
+                                                               }
+
+                                                               return calls.length > 0 ? "\n" + calls.join("\n") : "";
+                                               },
+
+                                               t: function (spy) {
+                                                               var objects = [];
+
+                                                               for (var i = 0, l = spy.callCount; i < l; ++i) {
+                                                                               push.call(objects, sinon.format(spy.thisValues[i]));
+                                                               }
+
+                                                               return objects.join(", ");
+                                               },
+
+                                               "*": function (spy, args) {
+                                                               var formatted = [];
+
+                                                               for (var i = 0, l = args.length; i < l; ++i) {
+                                                                               push.call(formatted, sinon.format(args[i]));
+                                                               }
+
+                                                               return formatted.join(", ");
+                                               }
+                               };
+
+                               sinon.extend(spy, spyApi);
+
+                               spy.spyCall = sinon.spyCall;
+                               sinon.spy = spy;
+
+                               return spy;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./call");
+                               require("./extend");
+                               require("./times_in_words");
+                               require("./format");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend extend.js
+ */
+/**
+ * Stub behavior
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Tim Fischbach (mail@timfischbach.de)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               var slice = Array.prototype.slice;
+               var join = Array.prototype.join;
+               var useLeftMostCallback = -1;
+               var useRightMostCallback = -2;
+
+               var nextTick = (function () {
+                               if (typeof process === "object" && typeof process.nextTick === "function") {
+                                               return process.nextTick;
+                               } else if (typeof setImmediate === "function") {
+                                               return setImmediate;
+                               } else {
+                                               return function (callback) {
+                                                               setTimeout(callback, 0);
+                                               };
+                               }
+               })();
+
+               function throwsException(error, message) {
+                               if (typeof error == "string") {
+                                               this.exception = new Error(message || "");
+                                               this.exception.name = error;
+                               } else if (!error) {
+                                               this.exception = new Error("Error");
+                               } else {
+                                               this.exception = error;
+                               }
+
+                               return this;
+               }
+
+               function getCallback(behavior, args) {
+                               var callArgAt = behavior.callArgAt;
+
+                               if (callArgAt >= 0) {
+                                               return args[callArgAt];
+                               }
+
+                               var argumentList;
+
+                               if (callArgAt === useLeftMostCallback) {
+                                               argumentList = args;
+                               }
+
+                               if (callArgAt === useRightMostCallback) {
+                                               argumentList = slice.call(args).reverse();
+                               }
+
+                               var callArgProp = behavior.callArgProp;
+
+                               for (var i = 0, l = argumentList.length; i < l; ++i) {
+                                               if (!callArgProp && typeof argumentList[i] == "function") {
+                                                               return argumentList[i];
+                                               }
+
+                                               if (callArgProp && argumentList[i] &&
+                                                               typeof argumentList[i][callArgProp] == "function") {
+                                                               return argumentList[i][callArgProp];
+                                               }
+                               }
+
+                               return null;
+               }
+
+               function makeApi(sinon) {
+                               function getCallbackError(behavior, func, args) {
+                                               if (behavior.callArgAt < 0) {
+                                                               var msg;
+
+                                                               if (behavior.callArgProp) {
+                                                                               msg = sinon.functionName(behavior.stub) +
+                                                                                               " expected to yield to '" + behavior.callArgProp +
+                                                                                               "', but no object with such a property was passed.";
+                                                               } else {
+                                                                               msg = sinon.functionName(behavior.stub) +
+                                                                                               " expected to yield, but no callback was passed.";
+                                                               }
+
+                                                               if (args.length > 0) {
+                                                                               msg += " Received [" + join.call(args, ", ") + "]";
+                                                               }
+
+                                                               return msg;
+                                               }
+
+                                               return "argument at index " + behavior.callArgAt + " is not a function: " + func;
+                               }
+
+                               function callCallback(behavior, args) {
+                                               if (typeof behavior.callArgAt == "number") {
+                                                               var func = getCallback(behavior, args);
+
+                                                               if (typeof func != "function") {
+                                                                               throw new TypeError(getCallbackError(behavior, func, args));
+                                                               }
+
+                                                               if (behavior.callbackAsync) {
+                                                                               nextTick(function () {
+                                                                                               func.apply(behavior.callbackContext, behavior.callbackArguments);
+                                                                               });
+                                                               } else {
+                                                                               func.apply(behavior.callbackContext, behavior.callbackArguments);
+                                                               }
+                                               }
+                               }
+
+                               var proto = {
+                                               create: function create(stub) {
+                                                               var behavior = sinon.extend({}, sinon.behavior);
+                                                               delete behavior.create;
+                                                               behavior.stub = stub;
+
+                                                               return behavior;
+                                               },
+
+                                               isPresent: function isPresent() {
+                                                               return (typeof this.callArgAt == "number" ||
+                                                                                               this.exception ||
+                                                                                               typeof this.returnArgAt == "number" ||
+                                                                                               this.returnThis ||
+                                                                                               this.returnValueDefined);
+                                               },
+
+                                               invoke: function invoke(context, args) {
+                                                               callCallback(this, args);
+
+                                                               if (this.exception) {
+                                                                               throw this.exception;
+                                                               } else if (typeof this.returnArgAt == "number") {
+                                                                               return args[this.returnArgAt];
+                                                               } else if (this.returnThis) {
+                                                                               return context;
+                                                               }
+
+                                                               return this.returnValue;
+                                               },
+
+                                               onCall: function onCall(index) {
+                                                               return this.stub.onCall(index);
+                                               },
+
+                                               onFirstCall: function onFirstCall() {
+                                                               return this.stub.onFirstCall();
+                                               },
+
+                                               onSecondCall: function onSecondCall() {
+                                                               return this.stub.onSecondCall();
+                                               },
+
+                                               onThirdCall: function onThirdCall() {
+                                                               return this.stub.onThirdCall();
+                                               },
+
+                                               withArgs: function withArgs(/* arguments */) {
+                                                               throw new Error("Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" is not supported. " +
+                                                                                                                               "Use \"stub.withArgs(...).onCall(...)\" to define sequential behavior for calls with certain arguments.");
+                                               },
+
+                                               callsArg: function callsArg(pos) {
+                                                               if (typeof pos != "number") {
+                                                                               throw new TypeError("argument index is not number");
+                                                               }
+
+                                                               this.callArgAt = pos;
+                                                               this.callbackArguments = [];
+                                                               this.callbackContext = undefined;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               callsArgOn: function callsArgOn(pos, context) {
+                                                               if (typeof pos != "number") {
+                                                                               throw new TypeError("argument index is not number");
+                                                               }
+                                                               if (typeof context != "object") {
+                                                                               throw new TypeError("argument context is not an object");
+                                                               }
+
+                                                               this.callArgAt = pos;
+                                                               this.callbackArguments = [];
+                                                               this.callbackContext = context;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               callsArgWith: function callsArgWith(pos) {
+                                                               if (typeof pos != "number") {
+                                                                               throw new TypeError("argument index is not number");
+                                                               }
+
+                                                               this.callArgAt = pos;
+                                                               this.callbackArguments = slice.call(arguments, 1);
+                                                               this.callbackContext = undefined;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               callsArgOnWith: function callsArgWith(pos, context) {
+                                                               if (typeof pos != "number") {
+                                                                               throw new TypeError("argument index is not number");
+                                                               }
+                                                               if (typeof context != "object") {
+                                                                               throw new TypeError("argument context is not an object");
+                                                               }
+
+                                                               this.callArgAt = pos;
+                                                               this.callbackArguments = slice.call(arguments, 2);
+                                                               this.callbackContext = context;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               yields: function () {
+                                                               this.callArgAt = useLeftMostCallback;
+                                                               this.callbackArguments = slice.call(arguments, 0);
+                                                               this.callbackContext = undefined;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               yieldsRight: function () {
+                                                               this.callArgAt = useRightMostCallback;
+                                                               this.callbackArguments = slice.call(arguments, 0);
+                                                               this.callbackContext = undefined;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               yieldsOn: function (context) {
+                                                               if (typeof context != "object") {
+                                                                               throw new TypeError("argument context is not an object");
+                                                               }
+
+                                                               this.callArgAt = useLeftMostCallback;
+                                                               this.callbackArguments = slice.call(arguments, 1);
+                                                               this.callbackContext = context;
+                                                               this.callArgProp = undefined;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               yieldsTo: function (prop) {
+                                                               this.callArgAt = useLeftMostCallback;
+                                                               this.callbackArguments = slice.call(arguments, 1);
+                                                               this.callbackContext = undefined;
+                                                               this.callArgProp = prop;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               yieldsToOn: function (prop, context) {
+                                                               if (typeof context != "object") {
+                                                                               throw new TypeError("argument context is not an object");
+                                                               }
+
+                                                               this.callArgAt = useLeftMostCallback;
+                                                               this.callbackArguments = slice.call(arguments, 2);
+                                                               this.callbackContext = context;
+                                                               this.callArgProp = prop;
+                                                               this.callbackAsync = false;
+
+                                                               return this;
+                                               },
+
+                                               throws: throwsException,
+                                               throwsException: throwsException,
+
+                                               returns: function returns(value) {
+                                                               this.returnValue = value;
+                                                               this.returnValueDefined = true;
+
+                                                               return this;
+                                               },
+
+                                               returnsArg: function returnsArg(pos) {
+                                                               if (typeof pos != "number") {
+                                                                               throw new TypeError("argument index is not number");
+                                                               }
+
+                                                               this.returnArgAt = pos;
+
+                                                               return this;
+                                               },
+
+                                               returnsThis: function returnsThis() {
+                                                               this.returnThis = true;
+
+                                                               return this;
+                                               }
+                               };
+
+                               // create asynchronous versions of callsArg* and yields* methods
+                               for (var method in proto) {
+                                               // need to avoid creating anotherasync versions of the newly added async methods
+                                               if (proto.hasOwnProperty(method) &&
+                                                               method.match(/^(callsArg|yields)/) &&
+                                                               !method.match(/Async/)) {
+                                                               proto[method + "Async"] = (function (syncFnName) {
+                                                                               return function () {
+                                                                                               var result = this[syncFnName].apply(this, arguments);
+                                                                                               this.callbackAsync = true;
+                                                                                               return result;
+                                                                               };
+                                                               })(method);
+                                               }
+                               }
+
+                               sinon.behavior = proto;
+                               return proto;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./extend");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend extend.js
+ * @depend spy.js
+ * @depend behavior.js
+ */
+/**
+ * Stub functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               function makeApi(sinon) {
+                               function stub(object, property, func) {
+                                               if (!!func && typeof func != "function" && typeof func != "object") {
+                                                               throw new TypeError("Custom stub should be a function or a property descriptor");
+                                               }
+
+                                               var wrapper;
+
+                                               if (func) {
+                                                               if (typeof func == "function") {
+                                                                               wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
+                                                               } else {
+                                                                               wrapper = func;
+                                                                               if (sinon.spy && sinon.spy.create) {
+                                                                                               var types = sinon.objectKeys(wrapper);
+                                                                                               for (var i = 0; i < types.length; i++) {
+                                                                                                               wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]);
+                                                                                               }
+                                                                               }
+                                                               }
+                                               } else {
+                                                               var stubLength = 0;
+                                                               if (typeof object == "object" && typeof object[property] == "function") {
+                                                                               stubLength = object[property].length;
+                                                               }
+                                                               wrapper = stub.create(stubLength);
+                                               }
+
+                                               if (!object && typeof property === "undefined") {
+                                                               return sinon.stub.create();
+                                               }
+
+                                               if (typeof property === "undefined" && typeof object == "object") {
+                                                               for (var prop in object) {
+                                                                               if (typeof object[prop] === "function") {
+                                                                                               stub(object, prop);
+                                                                               }
+                                                               }
+
+                                                               return object;
+                                               }
+
+                                               return sinon.wrapMethod(object, property, wrapper);
+                               }
+
+                               function getDefaultBehavior(stub) {
+                                               return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
+                               }
+
+                               function getParentBehaviour(stub) {
+                                               return (stub.parent && getCurrentBehavior(stub.parent));
+                               }
+
+                               function getCurrentBehavior(stub) {
+                                               var behavior = stub.behaviors[stub.callCount - 1];
+                                               return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
+                               }
+
+                               var uuid = 0;
+
+                               var proto = {
+                                               create: function create(stubLength) {
+                                                               var functionStub = function () {
+                                                                               return getCurrentBehavior(functionStub).invoke(this, arguments);
+                                                               };
+
+                                                               functionStub.id = "stub#" + uuid++;
+                                                               var orig = functionStub;
+                                                               functionStub = sinon.spy.create(functionStub, stubLength);
+                                                               functionStub.func = orig;
+
+                                                               sinon.extend(functionStub, stub);
+                                                               functionStub.instantiateFake = sinon.stub.create;
+                                                               functionStub.displayName = "stub";
+                                                               functionStub.toString = sinon.functionToString;
+
+                                                               functionStub.defaultBehavior = null;
+                                                               functionStub.behaviors = [];
+
+                                                               return functionStub;
+                                               },
+
+                                               resetBehavior: function () {
+                                                               var i;
+
+                                                               this.defaultBehavior = null;
+                                                               this.behaviors = [];
+
+                                                               delete this.returnValue;
+                                                               delete this.returnArgAt;
+                                                               this.returnThis = false;
+
+                                                               if (this.fakes) {
+                                                                               for (i = 0; i < this.fakes.length; i++) {
+                                                                                               this.fakes[i].resetBehavior();
+                                                                               }
+                                                               }
+                                               },
+
+                                               onCall: function onCall(index) {
+                                                               if (!this.behaviors[index]) {
+                                                                               this.behaviors[index] = sinon.behavior.create(this);
+                                                               }
+
+                                                               return this.behaviors[index];
+                                               },
+
+                                               onFirstCall: function onFirstCall() {
+                                                               return this.onCall(0);
+                                               },
+
+                                               onSecondCall: function onSecondCall() {
+                                                               return this.onCall(1);
+                                               },
+
+                                               onThirdCall: function onThirdCall() {
+                                                               return this.onCall(2);
+                                               }
+                               };
+
+                               for (var method in sinon.behavior) {
+                                               if (sinon.behavior.hasOwnProperty(method) &&
+                                                               !proto.hasOwnProperty(method) &&
+                                                               method != "create" &&
+                                                               method != "withArgs" &&
+                                                               method != "invoke") {
+                                                               proto[method] = (function (behaviorMethod) {
+                                                                               return function () {
+                                                                                               this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
+                                                                                               this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
+                                                                                               return this;
+                                                                               };
+                                                               }(method));
+                                               }
+                               }
+
+                               sinon.extend(stub, proto);
+                               sinon.stub = stub;
+
+                               return stub;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./behavior");
+                               require("./spy");
+                               require("./extend");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend times_in_words.js
+ * @depend util/core.js
+ * @depend call.js
+ * @depend extend.js
+ * @depend match.js
+ * @depend spy.js
+ * @depend stub.js
+ * @depend format.js
+ */
+/**
+ * Mock functions.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               function makeApi(sinon) {
+                               var push = [].push;
+                               var match = sinon.match;
+
+                               function mock(object) {
+                                               if (!object) {
+                                                               return sinon.expectation.create("Anonymous mock");
+                                               }
+
+                                               return mock.create(object);
+                               }
+
+                               function each(collection, callback) {
+                                               if (!collection) {
+                                                               return;
+                                               }
+
+                                               for (var i = 0, l = collection.length; i < l; i += 1) {
+                                                               callback(collection[i]);
+                                               }
+                               }
+
+                               sinon.extend(mock, {
+                                               create: function create(object) {
+                                                               if (!object) {
+                                                                               throw new TypeError("object is null");
+                                                               }
+
+                                                               var mockObject = sinon.extend({}, mock);
+                                                               mockObject.object = object;
+                                                               delete mockObject.create;
+
+                                                               return mockObject;
+                                               },
+
+                                               expects: function expects(method) {
+                                                               if (!method) {
+                                                                               throw new TypeError("method is falsy");
+                                                               }
+
+                                                               if (!this.expectations) {
+                                                                               this.expectations = {};
+                                                                               this.proxies = [];
+                                                               }
+
+                                                               if (!this.expectations[method]) {
+                                                                               this.expectations[method] = [];
+                                                                               var mockObject = this;
+
+                                                                               sinon.wrapMethod(this.object, method, function () {
+                                                                                               return mockObject.invokeMethod(method, this, arguments);
+                                                                               });
+
+                                                                               push.call(this.proxies, method);
+                                                               }
+
+                                                               var expectation = sinon.expectation.create(method);
+                                                               push.call(this.expectations[method], expectation);
+
+                                                               return expectation;
+                                               },
+
+                                               restore: function restore() {
+                                                               var object = this.object;
+
+                                                               each(this.proxies, function (proxy) {
+                                                                               if (typeof object[proxy].restore == "function") {
+                                                                                               object[proxy].restore();
+                                                                               }
+                                                               });
+                                               },
+
+                                               verify: function verify() {
+                                                               var expectations = this.expectations || {};
+                                                               var messages = [], met = [];
+
+                                                               each(this.proxies, function (proxy) {
+                                                                               each(expectations[proxy], function (expectation) {
+                                                                                               if (!expectation.met()) {
+                                                                                                               push.call(messages, expectation.toString());
+                                                                                               } else {
+                                                                                                               push.call(met, expectation.toString());
+                                                                                               }
+                                                                               });
+                                                               });
+
+                                                               this.restore();
+
+                                                               if (messages.length > 0) {
+                                                                               sinon.expectation.fail(messages.concat(met).join("\n"));
+                                                               } else if (met.length > 0) {
+                                                                               sinon.expectation.pass(messages.concat(met).join("\n"));
+                                                               }
+
+                                                               return true;
+                                               },
+
+                                               invokeMethod: function invokeMethod(method, thisValue, args) {
+                                                               var expectations = this.expectations && this.expectations[method];
+                                                               var length = expectations && expectations.length || 0, i;
+
+                                                               for (i = 0; i < length; i += 1) {
+                                                                               if (!expectations[i].met() &&
+                                                                                               expectations[i].allowsCall(thisValue, args)) {
+                                                                                               return expectations[i].apply(thisValue, args);
+                                                                               }
+                                                               }
+
+                                                               var messages = [], available, exhausted = 0;
+
+                                                               for (i = 0; i < length; i += 1) {
+                                                                               if (expectations[i].allowsCall(thisValue, args)) {
+                                                                                               available = available || expectations[i];
+                                                                               } else {
+                                                                                               exhausted += 1;
+                                                                               }
+                                                                               push.call(messages, "    " + expectations[i].toString());
+                                                               }
+
+                                                               if (exhausted === 0) {
+                                                                               return available.apply(thisValue, args);
+                                                               }
+
+                                                               messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
+                                                                               proxy: method,
+                                                                               args: args
+                                                               }));
+
+                                                               sinon.expectation.fail(messages.join("\n"));
+                                               }
+                               });
+
+                               var times = sinon.timesInWords;
+                               var slice = Array.prototype.slice;
+
+                               function callCountInWords(callCount) {
+                                               if (callCount == 0) {
+                                                               return "never called";
+                                               } else {
+                                                               return "called " + times(callCount);
+                                               }
+                               }
+
+                               function expectedCallCountInWords(expectation) {
+                                               var min = expectation.minCalls;
+                                               var max = expectation.maxCalls;
+
+                                               if (typeof min == "number" && typeof max == "number") {
+                                                               var str = times(min);
+
+                                                               if (min != max) {
+                                                                               str = "at least " + str + " and at most " + times(max);
+                                                               }
+
+                                                               return str;
+                                               }
+
+                                               if (typeof min == "number") {
+                                                               return "at least " + times(min);
+                                               }
+
+                                               return "at most " + times(max);
+                               }
+
+                               function receivedMinCalls(expectation) {
+                                               var hasMinLimit = typeof expectation.minCalls == "number";
+                                               return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+                               }
+
+                               function receivedMaxCalls(expectation) {
+                                               if (typeof expectation.maxCalls != "number") {
+                                                               return false;
+                                               }
+
+                                               return expectation.callCount == expectation.maxCalls;
+                               }
+
+                               function verifyMatcher(possibleMatcher, arg) {
+                                               if (match && match.isMatcher(possibleMatcher)) {
+                                                               return possibleMatcher.test(arg);
+                                               } else {
+                                                               return true;
+                                               }
+                               }
+
+                               sinon.expectation = {
+                                               minCalls: 1,
+                                               maxCalls: 1,
+
+                                               create: function create(methodName) {
+                                                               var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
+                                                               delete expectation.create;
+                                                               expectation.method = methodName;
+
+                                                               return expectation;
+                                               },
+
+                                               invoke: function invoke(func, thisValue, args) {
+                                                               this.verifyCallAllowed(thisValue, args);
+
+                                                               return sinon.spy.invoke.apply(this, arguments);
+                                               },
+
+                                               atLeast: function atLeast(num) {
+                                                               if (typeof num != "number") {
+                                                                               throw new TypeError("'" + num + "' is not number");
+                                                               }
+
+                                                               if (!this.limitsSet) {
+                                                                               this.maxCalls = null;
+                                                                               this.limitsSet = true;
+                                                               }
+
+                                                               this.minCalls = num;
+
+                                                               return this;
+                                               },
+
+                                               atMost: function atMost(num) {
+                                                               if (typeof num != "number") {
+                                                                               throw new TypeError("'" + num + "' is not number");
+                                                               }
+
+                                                               if (!this.limitsSet) {
+                                                                               this.minCalls = null;
+                                                                               this.limitsSet = true;
+                                                               }
+
+                                                               this.maxCalls = num;
+
+                                                               return this;
+                                               },
+
+                                               never: function never() {
+                                                               return this.exactly(0);
+                                               },
+
+                                               once: function once() {
+                                                               return this.exactly(1);
+                                               },
+
+                                               twice: function twice() {
+                                                               return this.exactly(2);
+                                               },
+
+                                               thrice: function thrice() {
+                                                               return this.exactly(3);
+                                               },
+
+                                               exactly: function exactly(num) {
+                                                               if (typeof num != "number") {
+                                                                               throw new TypeError("'" + num + "' is not a number");
+                                                               }
+
+                                                               this.atLeast(num);
+                                                               return this.atMost(num);
+                                               },
+
+                                               met: function met() {
+                                                               return !this.failed && receivedMinCalls(this);
+                                               },
+
+                                               verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+                                                               if (receivedMaxCalls(this)) {
+                                                                               this.failed = true;
+                                                                               sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
+                                                               }
+
+                                                               if ("expectedThis" in this && this.expectedThis !== thisValue) {
+                                                                               sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
+                                                                                               this.expectedThis);
+                                                               }
+
+                                                               if (!("expectedArguments" in this)) {
+                                                                               return;
+                                                               }
+
+                                                               if (!args) {
+                                                                               sinon.expectation.fail(this.method + " received no arguments, expected " +
+                                                                                               sinon.format(this.expectedArguments));
+                                                               }
+
+                                                               if (args.length < this.expectedArguments.length) {
+                                                                               sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
+                                                                                               "), expected " + sinon.format(this.expectedArguments));
+                                                               }
+
+                                                               if (this.expectsExactArgCount &&
+                                                                               args.length != this.expectedArguments.length) {
+                                                                               sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
+                                                                                               "), expected " + sinon.format(this.expectedArguments));
+                                                               }
+
+                                                               for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+
+                                                                               if (!verifyMatcher(this.expectedArguments[i], args[i])) {
+                                                                                               sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+                                                                                                               ", didn't match " + this.expectedArguments.toString());
+                                                                               }
+
+                                                                               if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+                                                                                               sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+                                                                                                               ", expected " + sinon.format(this.expectedArguments));
+                                                                               }
+                                                               }
+                                               },
+
+                                               allowsCall: function allowsCall(thisValue, args) {
+                                                               if (this.met() && receivedMaxCalls(this)) {
+                                                                               return false;
+                                                               }
+
+                                                               if ("expectedThis" in this && this.expectedThis !== thisValue) {
+                                                                               return false;
+                                                               }
+
+                                                               if (!("expectedArguments" in this)) {
+                                                                               return true;
+                                                               }
+
+                                                               args = args || [];
+
+                                                               if (args.length < this.expectedArguments.length) {
+                                                                               return false;
+                                                               }
+
+                                                               if (this.expectsExactArgCount &&
+                                                                               args.length != this.expectedArguments.length) {
+                                                                               return false;
+                                                               }
+
+                                                               for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+                                                                               if (!verifyMatcher(this.expectedArguments[i], args[i])) {
+                                                                                               return false;
+                                                                               }
+
+                                                                               if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+                                                                                               return false;
+                                                                               }
+                                                               }
+
+                                                               return true;
+                                               },
+
+                                               withArgs: function withArgs() {
+                                                               this.expectedArguments = slice.call(arguments);
+                                                               return this;
+                                               },
+
+                                               withExactArgs: function withExactArgs() {
+                                                               this.withArgs.apply(this, arguments);
+                                                               this.expectsExactArgCount = true;
+                                                               return this;
+                                               },
+
+                                               on: function on(thisValue) {
+                                                               this.expectedThis = thisValue;
+                                                               return this;
+                                               },
+
+                                               toString: function () {
+                                                               var args = (this.expectedArguments || []).slice();
+
+                                                               if (!this.expectsExactArgCount) {
+                                                                               push.call(args, "[...]");
+                                                               }
+
+                                                               var callStr = sinon.spyCall.toString.call({
+                                                                               proxy: this.method || "anonymous mock expectation",
+                                                                               args: args
+                                                               });
+
+                                                               var message = callStr.replace(", [...", "[, ...") + " " +
+                                                                               expectedCallCountInWords(this);
+
+                                                               if (this.met()) {
+                                                                               return "Expectation met: " + message;
+                                                               }
+
+                                                               return "Expected " + message + " (" +
+                                                                               callCountInWords(this.callCount) + ")";
+                                               },
+
+                                               verify: function verify() {
+                                                               if (!this.met()) {
+                                                                               sinon.expectation.fail(this.toString());
+                                                               } else {
+                                                                               sinon.expectation.pass(this.toString());
+                                                               }
+
+                                                               return true;
+                                               },
+
+                                               pass: function pass(message) {
+                                                               sinon.assert.pass(message);
+                                               },
+
+                                               fail: function fail(message) {
+                                                               var exception = new Error(message);
+                                                               exception.name = "ExpectationError";
+
+                                                               throw exception;
+                                               }
+                               };
+
+                               sinon.mock = mock;
+                               return mock;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./times_in_words");
+                               require("./call");
+                               require("./extend");
+                               require("./match");
+                               require("./spy");
+                               require("./stub");
+                               require("./format");
+
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend spy.js
+ * @depend stub.js
+ * @depend mock.js
+ */
+/**
+ * Collections of stubs, spies and mocks.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               var push = [].push;
+               var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+               function getFakes(fakeCollection) {
+                               if (!fakeCollection.fakes) {
+                                               fakeCollection.fakes = [];
+                               }
+
+                               return fakeCollection.fakes;
+               }
+
+               function each(fakeCollection, method) {
+                               var fakes = getFakes(fakeCollection);
+
+                               for (var i = 0, l = fakes.length; i < l; i += 1) {
+                                               if (typeof fakes[i][method] == "function") {
+                                                               fakes[i][method]();
+                                               }
+                               }
+               }
+
+               function compact(fakeCollection) {
+                               var fakes = getFakes(fakeCollection);
+                               var i = 0;
+                               while (i < fakes.length) {
+                                               fakes.splice(i, 1);
+                               }
+               }
+
+               function makeApi(sinon) {
+                               var collection = {
+                                               verify: function resolve() {
+                                                               each(this, "verify");
+                                               },
+
+                                               restore: function restore() {
+                                                               each(this, "restore");
+                                                               compact(this);
+                                               },
+
+                                               reset: function restore() {
+                                                               each(this, "reset");
+                                               },
+
+                                               verifyAndRestore: function verifyAndRestore() {
+                                                               var exception;
+
+                                                               try {
+                                                                               this.verify();
+                                                               } catch (e) {
+                                                                               exception = e;
+                                                               }
+
+                                                               this.restore();
+
+                                                               if (exception) {
+                                                                               throw exception;
+                                                               }
+                                               },
+
+                                               add: function add(fake) {
+                                                               push.call(getFakes(this), fake);
+                                                               return fake;
+                                               },
+
+                                               spy: function spy() {
+                                                               return this.add(sinon.spy.apply(sinon, arguments));
+                                               },
+
+                                               stub: function stub(object, property, value) {
+                                                               if (property) {
+                                                                               var original = object[property];
+
+                                                                               if (typeof original != "function") {
+                                                                                               if (!hasOwnProperty.call(object, property)) {
+                                                                                                               throw new TypeError("Cannot stub non-existent own property " + property);
+                                                                                               }
+
+                                                                                               object[property] = value;
+
+                                                                                               return this.add({
+                                                                                                               restore: function () {
+                                                                                                                               object[property] = original;
+                                                                                                               }
+                                                                                               });
+                                                                               }
+                                                               }
+                                                               if (!property && !!object && typeof object == "object") {
+                                                                               var stubbedObj = sinon.stub.apply(sinon, arguments);
+
+                                                                               for (var prop in stubbedObj) {
+                                                                                               if (typeof stubbedObj[prop] === "function") {
+                                                                                                               this.add(stubbedObj[prop]);
+                                                                                               }
+                                                                               }
+
+                                                                               return stubbedObj;
+                                                               }
+
+                                                               return this.add(sinon.stub.apply(sinon, arguments));
+                                               },
+
+                                               mock: function mock() {
+                                                               return this.add(sinon.mock.apply(sinon, arguments));
+                                               },
+
+                                               inject: function inject(obj) {
+                                                               var col = this;
+
+                                                               obj.spy = function () {
+                                                                               return col.spy.apply(col, arguments);
+                                                               };
+
+                                                               obj.stub = function () {
+                                                                               return col.stub.apply(col, arguments);
+                                                               };
+
+                                                               obj.mock = function () {
+                                                                               return col.mock.apply(col, arguments);
+                                                               };
+
+                                                               return obj;
+                                               }
+                               };
+
+                               sinon.collection = collection;
+                               return collection;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./mock");
+                               require("./spy");
+                               require("./stub");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/*global lolex */
+
+/**
+ * Fake timer API
+ * setTimeout
+ * setInterval
+ * clearTimeout
+ * clearInterval
+ * tick
+ * reset
+ * Date
+ *
+ * Inspired by jsUnitMockTimeOut from JsUnit
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+               var sinon = {};
+}
+
+(function (global) {
+               function makeApi(sinon, lol) {
+                               var llx = typeof lolex !== "undefined" ? lolex : lol;
+
+                               sinon.useFakeTimers = function () {
+                                               var now, methods = Array.prototype.slice.call(arguments);
+
+                                               if (typeof methods[0] === "string") {
+                                                               now = 0;
+                                               } else {
+                                                               now = methods.shift();
+                                               }
+
+                                               var clock = llx.install(now || 0, methods);
+                                               clock.restore = clock.uninstall;
+                                               return clock;
+                               };
+
+                               sinon.clock = {
+                                               create: function (now) {
+                                                               return llx.createClock(now);
+                                               }
+                               };
+
+                               sinon.timers = {
+                                               setTimeout: setTimeout,
+                                               clearTimeout: clearTimeout,
+                                               setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+                                               clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined),
+                                               setInterval: setInterval,
+                                               clearInterval: clearInterval,
+                                               Date: Date
+                               };
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, epxorts, module, lolex) {
+                               var sinon = require("./core");
+                               makeApi(sinon, lolex);
+                               module.exports = sinon;
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module, require("lolex"));
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof global != "undefined" && typeof global !== "function" ? global : this));
+
+/**
+ * Minimal Event interface implementation
+ *
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
+ * Modifications and tests by Christian Johansen.
+ *
+ * @author Sven Fuchs (svenfuchs@artweb-design.de)
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+               this.sinon = {};
+}
+
+(function () {
+               var push = [].push;
+
+               function makeApi(sinon) {
+                               sinon.Event = function Event(type, bubbles, cancelable, target) {
+                                               this.initEvent(type, bubbles, cancelable, target);
+                               };
+
+                               sinon.Event.prototype = {
+                                               initEvent: function (type, bubbles, cancelable, target) {
+                                                               this.type = type;
+                                                               this.bubbles = bubbles;
+                                                               this.cancelable = cancelable;
+                                                               this.target = target;
+                                               },
+
+                                               stopPropagation: function () {},
+
+                                               preventDefault: function () {
+                                                               this.defaultPrevented = true;
+                                               }
+                               };
+
+                               sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
+                                               this.initEvent(type, false, false, target);
+                                               this.loaded = progressEventRaw.loaded || null;
+                                               this.total = progressEventRaw.total || null;
+                                               this.lengthComputable = !!progressEventRaw.total;
+                               };
+
+                               sinon.ProgressEvent.prototype = new sinon.Event();
+
+                               sinon.ProgressEvent.prototype.constructor =  sinon.ProgressEvent;
+
+                               sinon.CustomEvent = function CustomEvent(type, customData, target) {
+                                               this.initEvent(type, false, false, target);
+                                               this.detail = customData.detail || null;
+                               };
+
+                               sinon.CustomEvent.prototype = new sinon.Event();
+
+                               sinon.CustomEvent.prototype.constructor =  sinon.CustomEvent;
+
+                               sinon.EventTarget = {
+                                               addEventListener: function addEventListener(event, listener) {
+                                                               this.eventListeners = this.eventListeners || {};
+                                                               this.eventListeners[event] = this.eventListeners[event] || [];
+                                                               push.call(this.eventListeners[event], listener);
+                                               },
+
+                                               removeEventListener: function removeEventListener(event, listener) {
+                                                               var listeners = this.eventListeners && this.eventListeners[event] || [];
+
+                                                               for (var i = 0, l = listeners.length; i < l; ++i) {
+                                                                               if (listeners[i] == listener) {
+                                                                                               return listeners.splice(i, 1);
+                                                                               }
+                                                               }
+                                               },
+
+                                               dispatchEvent: function dispatchEvent(event) {
+                                                               var type = event.type;
+                                                               var listeners = this.eventListeners && this.eventListeners[type] || [];
+
+                                                               for (var i = 0; i < listeners.length; i++) {
+                                                                               if (typeof listeners[i] == "function") {
+                                                                                               listeners[i].call(this, event);
+                                                                               } else {
+                                                                                               listeners[i].handleEvent(event);
+                                                                               }
+                                                               }
+
+                                                               return !!event.defaultPrevented;
+                                               }
+                               };
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require) {
+                               var sinon = require("./core");
+                               makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require);
+               } else {
+                               makeApi(sinon);
+               }
+}());
+
+/**
+ * @depend util/core.js
+ */
+/**
+ * Logs errors
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+(function (sinon) {
+               // cache a reference to setTimeout, so that our reference won't be stubbed out
+               // when using fake timers and errors will still get logged
+               // https://github.com/cjohansen/Sinon.JS/issues/381
+               var realSetTimeout = setTimeout;
+
+               function makeApi(sinon) {
+
+                               function log() {}
+
+                               function logError(label, err) {
+                                               var msg = label + " threw exception: ";
+
+                                               sinon.log(msg + "[" + err.name + "] " + err.message);
+
+                                               if (err.stack) {
+                                                               sinon.log(err.stack);
+                                               }
+
+                                               logError.setTimeout(function () {
+                                                               err.message = msg + err.message;
+                                                               throw err;
+                                               }, 0);
+                               };
+
+                               // wrap realSetTimeout with something we can stub in tests
+                               logError.setTimeout = function (func, timeout) {
+                                               realSetTimeout(func, timeout);
+                               }
+
+                               var exports = {};
+                               exports.log = sinon.log = log;
+                               exports.logError = sinon.logError = logError;
+
+                               return exports;
+               }
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               module.exports = makeApi(sinon);
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend core.js
+ * @depend ../extend.js
+ * @depend event.js
+ * @depend ../log_error.js
+ */
+/**
+ * Fake XDomainRequest object
+ */
+
+if (typeof sinon == "undefined") {
+               this.sinon = {};
+}
+
+// wrapper for global
+(function (global) {
+               var xdr = { XDomainRequest: global.XDomainRequest };
+               xdr.GlobalXDomainRequest = global.XDomainRequest;
+               xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
+               xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest :  false;
+
+               function makeApi(sinon) {
+                               sinon.xdr = xdr;
+
+                               function FakeXDomainRequest() {
+                                               this.readyState = FakeXDomainRequest.UNSENT;
+                                               this.requestBody = null;
+                                               this.requestHeaders = {};
+                                               this.status = 0;
+                                               this.timeout = null;
+
+                                               if (typeof FakeXDomainRequest.onCreate == "function") {
+                                                               FakeXDomainRequest.onCreate(this);
+                                               }
+                               }
+
+                               function verifyState(xdr) {
+                                               if (xdr.readyState !== FakeXDomainRequest.OPENED) {
+                                                               throw new Error("INVALID_STATE_ERR");
+                                               }
+
+                                               if (xdr.sendFlag) {
+                                                               throw new Error("INVALID_STATE_ERR");
+                                               }
+                               }
+
+                               function verifyRequestSent(xdr) {
+                                               if (xdr.readyState == FakeXDomainRequest.UNSENT) {
+                                                               throw new Error("Request not sent");
+                                               }
+                                               if (xdr.readyState == FakeXDomainRequest.DONE) {
+                                                               throw new Error("Request done");
+                                               }
+                               }
+
+                               function verifyResponseBodyType(body) {
+                                               if (typeof body != "string") {
+                                                               var error = new Error("Attempted to respond to fake XDomainRequest with " +
+                                                                                                                                               body + ", which is not a string.");
+                                                               error.name = "InvalidBodyException";
+                                                               throw error;
+                                               }
+                               }
+
+                               sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
+                                               open: function open(method, url) {
+                                                               this.method = method;
+                                                               this.url = url;
+
+                                                               this.responseText = null;
+                                                               this.sendFlag = false;
+
+                                                               this.readyStateChange(FakeXDomainRequest.OPENED);
+                                               },
+
+                                               readyStateChange: function readyStateChange(state) {
+                                                               this.readyState = state;
+                                                               var eventName = "";
+                                                               switch (this.readyState) {
+                                                               case FakeXDomainRequest.UNSENT:
+                                                                               break;
+                                                               case FakeXDomainRequest.OPENED:
+                                                                               break;
+                                                               case FakeXDomainRequest.LOADING:
+                                                                               if (this.sendFlag) {
+                                                                                               //raise the progress event
+                                                                                               eventName = "onprogress";
+                                                                               }
+                                                                               break;
+                                                               case FakeXDomainRequest.DONE:
+                                                                               if (this.isTimeout) {
+                                                                                               eventName = "ontimeout"
+                                                                               } else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
+                                                                                               eventName = "onerror";
+                                                                               } else {
+                                                                                               eventName = "onload"
+                                                                               }
+                                                                               break;
+                                                               }
+
+                                                               // raising event (if defined)
+                                                               if (eventName) {
+                                                                               if (typeof this[eventName] == "function") {
+                                                                                               try {
+                                                                                                               this[eventName]();
+                                                                                               } catch (e) {
+                                                                                                               sinon.logError("Fake XHR " + eventName + " handler", e);
+                                                                                               }
+                                                                               }
+                                                               }
+                                               },
+
+                                               send: function send(data) {
+                                                               verifyState(this);
+
+                                                               if (!/^(get|head)$/i.test(this.method)) {
+                                                                               this.requestBody = data;
+                                                               }
+                                                               this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+
+                                                               this.errorFlag = false;
+                                                               this.sendFlag = true;
+                                                               this.readyStateChange(FakeXDomainRequest.OPENED);
+
+                                                               if (typeof this.onSend == "function") {
+                                                                               this.onSend(this);
+                                                               }
+                                               },
+
+                                               abort: function abort() {
+                                                               this.aborted = true;
+                                                               this.responseText = null;
+                                                               this.errorFlag = true;
+
+                                                               if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
+                                                                               this.readyStateChange(sinon.FakeXDomainRequest.DONE);
+                                                                               this.sendFlag = false;
+                                                               }
+                                               },
+
+                                               setResponseBody: function setResponseBody(body) {
+                                                               verifyRequestSent(this);
+                                                               verifyResponseBodyType(body);
+
+                                                               var chunkSize = this.chunkSize || 10;
+                                                               var index = 0;
+                                                               this.responseText = "";
+
+                                                               do {
+                                                                               this.readyStateChange(FakeXDomainRequest.LOADING);
+                                                                               this.responseText += body.substring(index, index + chunkSize);
+                                                                               index += chunkSize;
+                                                               } while (index < body.length);
+
+                                                               this.readyStateChange(FakeXDomainRequest.DONE);
+                                               },
+
+                                               respond: function respond(status, contentType, body) {
+                                                               // content-type ignored, since XDomainRequest does not carry this
+                                                               // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
+                                                               // test integration across browsers
+                                                               this.status = typeof status == "number" ? status : 200;
+                                                               this.setResponseBody(body || "");
+                                               },
+
+                                               simulatetimeout: function simulatetimeout() {
+                                                               this.status = 0;
+                                                               this.isTimeout = true;
+                                                               // Access to this should actually throw an error
+                                                               this.responseText = undefined;
+                                                               this.readyStateChange(FakeXDomainRequest.DONE);
+                                               }
+                               });
+
+                               sinon.extend(FakeXDomainRequest, {
+                                               UNSENT: 0,
+                                               OPENED: 1,
+                                               LOADING: 3,
+                                               DONE: 4
+                               });
+
+                               sinon.useFakeXDomainRequest = function useFakeXDomainRequest() {
+                                               sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
+                                                               if (xdr.supportsXDR) {
+                                                                               global.XDomainRequest = xdr.GlobalXDomainRequest;
+                                                               }
+
+                                                               delete sinon.FakeXDomainRequest.restore;
+
+                                                               if (keepOnCreate !== true) {
+                                                                               delete sinon.FakeXDomainRequest.onCreate;
+                                                               }
+                                               };
+                                               if (xdr.supportsXDR) {
+                                                               global.XDomainRequest = sinon.FakeXDomainRequest;
+                                               }
+                                               return sinon.FakeXDomainRequest;
+                               };
+
+                               sinon.FakeXDomainRequest = FakeXDomainRequest;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./core");
+                               require("../extend");
+                               require("./event");
+                               require("../log_error");
+                               makeApi(sinon);
+                               module.exports = sinon;
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else {
+                               makeApi(sinon);
+               }
+})(this);
+
+/**
+ * @depend core.js
+ * @depend ../extend.js
+ * @depend event.js
+ * @depend ../log_error.js
+ */
+/**
+ * Fake XMLHttpRequest object
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (global) {
+
+               var supportsProgress = typeof ProgressEvent !== "undefined";
+               var supportsCustomEvent = typeof CustomEvent !== "undefined";
+               var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest };
+               sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+               sinonXhr.GlobalActiveXObject = global.ActiveXObject;
+               sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject != "undefined";
+               sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest != "undefined";
+               sinonXhr.workingXHR = sinonXhr.supportsXHR ? sinonXhr.GlobalXMLHttpRequest : sinonXhr.supportsActiveX
+                                                                                                                                                ? function () { return new sinonXhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
+               sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest());
+
+               /*jsl:ignore*/
+               var unsafeHeaders = {
+                               "Accept-Charset": true,
+                               "Accept-Encoding": true,
+                               Connection: true,
+                               "Content-Length": true,
+                               Cookie: true,
+                               Cookie2: true,
+                               "Content-Transfer-Encoding": true,
+                               Date: true,
+                               Expect: true,
+                               Host: true,
+                               "Keep-Alive": true,
+                               Referer: true,
+                               TE: true,
+                               Trailer: true,
+                               "Transfer-Encoding": true,
+                               Upgrade: true,
+                               "User-Agent": true,
+                               Via: true
+               };
+               /*jsl:end*/
+
+               function FakeXMLHttpRequest() {
+                               this.readyState = FakeXMLHttpRequest.UNSENT;
+                               this.requestHeaders = {};
+                               this.requestBody = null;
+                               this.status = 0;
+                               this.statusText = "";
+                               this.upload = new UploadProgress();
+                               if (sinonXhr.supportsCORS) {
+                                               this.withCredentials = false;
+                               }
+
+                               var xhr = this;
+                               var events = ["loadstart", "load", "abort", "loadend"];
+
+                               function addEventListener(eventName) {
+                                               xhr.addEventListener(eventName, function (event) {
+                                                               var listener = xhr["on" + eventName];
+
+                                                               if (listener && typeof listener == "function") {
+                                                                               listener.call(this, event);
+                                                               }
+                                               });
+                               }
+
+                               for (var i = events.length - 1; i >= 0; i--) {
+                                               addEventListener(events[i]);
+                               }
+
+                               if (typeof FakeXMLHttpRequest.onCreate == "function") {
+                                               FakeXMLHttpRequest.onCreate(this);
+                               }
+               }
+
+               // An upload object is created for each
+               // FakeXMLHttpRequest and allows upload
+               // events to be simulated using uploadProgress
+               // and uploadError.
+               function UploadProgress() {
+                               this.eventListeners = {
+                                               progress: [],
+                                               load: [],
+                                               abort: [],
+                                               error: []
+                               }
+               }
+
+               UploadProgress.prototype.addEventListener = function addEventListener(event, listener) {
+                               this.eventListeners[event].push(listener);
+               };
+
+               UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) {
+                               var listeners = this.eventListeners[event] || [];
+
+                               for (var i = 0, l = listeners.length; i < l; ++i) {
+                                               if (listeners[i] == listener) {
+                                                               return listeners.splice(i, 1);
+                                               }
+                               }
+               };
+
+               UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) {
+                               var listeners = this.eventListeners[event.type] || [];
+
+                               for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
+                                               listener(event);
+                               }
+               };
+
+               function verifyState(xhr) {
+                               if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+                                               throw new Error("INVALID_STATE_ERR");
+                               }
+
+                               if (xhr.sendFlag) {
+                                               throw new Error("INVALID_STATE_ERR");
+                               }
+               }
+
+               function getHeader(headers, header) {
+                               header = header.toLowerCase();
+
+                               for (var h in headers) {
+                                               if (h.toLowerCase() == header) {
+                                                               return h;
+                                               }
+                               }
+
+                               return null;
+               }
+
+               // filtering to enable a white-list version of Sinon FakeXhr,
+               // where whitelisted requests are passed through to real XHR
+               function each(collection, callback) {
+                               if (!collection) {
+                                               return;
+                               }
+
+                               for (var i = 0, l = collection.length; i < l; i += 1) {
+                                               callback(collection[i]);
+                               }
+               }
+               function some(collection, callback) {
+                               for (var index = 0; index < collection.length; index++) {
+                                               if (callback(collection[index]) === true) {
+                                                               return true;
+                                               }
+                               }
+                               return false;
+               }
+               // largest arity in XHR is 5 - XHR#open
+               var apply = function (obj, method, args) {
+                               switch (args.length) {
+                               case 0: return obj[method]();
+                               case 1: return obj[method](args[0]);
+                               case 2: return obj[method](args[0], args[1]);
+                               case 3: return obj[method](args[0], args[1], args[2]);
+                               case 4: return obj[method](args[0], args[1], args[2], args[3]);
+                               case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]);
+                               }
+               };
+
+               FakeXMLHttpRequest.filters = [];
+               FakeXMLHttpRequest.addFilter = function addFilter(fn) {
+                               this.filters.push(fn)
+               };
+               var IE6Re = /MSIE 6/;
+               FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) {
+                               var xhr = new sinonXhr.workingXHR();
+                               each([
+                                               "open",
+                                               "setRequestHeader",
+                                               "send",
+                                               "abort",
+                                               "getResponseHeader",
+                                               "getAllResponseHeaders",
+                                               "addEventListener",
+                                               "overrideMimeType",
+                                               "removeEventListener"
+                               ], function (method) {
+                                               fakeXhr[method] = function () {
+                                                               return apply(xhr, method, arguments);
+                                               };
+                               });
+
+                               var copyAttrs = function (args) {
+                                               each(args, function (attr) {
+                                                               try {
+                                                                               fakeXhr[attr] = xhr[attr]
+                                                               } catch (e) {
+                                                                               if (!IE6Re.test(navigator.userAgent)) {
+                                                                                               throw e;
+                                                                               }
+                                                               }
+                                               });
+                               };
+
+                               var stateChange = function stateChange() {
+                                               fakeXhr.readyState = xhr.readyState;
+                                               if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                                                               copyAttrs(["status", "statusText"]);
+                                               }
+                                               if (xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+                                                               copyAttrs(["responseText", "response"]);
+                                               }
+                                               if (xhr.readyState === FakeXMLHttpRequest.DONE) {
+                                                               copyAttrs(["responseXML"]);
+                                               }
+                                               if (fakeXhr.onreadystatechange) {
+                                                               fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
+                                               }
+                               };
+
+                               if (xhr.addEventListener) {
+                                               for (var event in fakeXhr.eventListeners) {
+                                                               if (fakeXhr.eventListeners.hasOwnProperty(event)) {
+                                                                               each(fakeXhr.eventListeners[event], function (handler) {
+                                                                                               xhr.addEventListener(event, handler);
+                                                                               });
+                                                               }
+                                               }
+                                               xhr.addEventListener("readystatechange", stateChange);
+                               } else {
+                                               xhr.onreadystatechange = stateChange;
+                               }
+                               apply(xhr, "open", xhrArgs);
+               };
+               FakeXMLHttpRequest.useFilters = false;
+
+               function verifyRequestOpened(xhr) {
+                               if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
+                                               throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
+                               }
+               }
+
+               function verifyRequestSent(xhr) {
+                               if (xhr.readyState == FakeXMLHttpRequest.DONE) {
+                                               throw new Error("Request done");
+                               }
+               }
+
+               function verifyHeadersReceived(xhr) {
+                               if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                                               throw new Error("No headers received");
+                               }
+               }
+
+               function verifyResponseBodyType(body) {
+                               if (typeof body != "string") {
+                                               var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+                                                                                                                                body + ", which is not a string.");
+                                               error.name = "InvalidBodyException";
+                                               throw error;
+                               }
+               }
+
+               FakeXMLHttpRequest.parseXML = function parseXML(text) {
+                               var xmlDoc;
+
+                               if (typeof DOMParser != "undefined") {
+                                               var parser = new DOMParser();
+                                               xmlDoc = parser.parseFromString(text, "text/xml");
+                               } else {
+                                               xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+                                               xmlDoc.async = "false";
+                                               xmlDoc.loadXML(text);
+                               }
+
+                               return xmlDoc;
+               };
+
+               FakeXMLHttpRequest.statusCodes = {
+                               100: "Continue",
+                               101: "Switching Protocols",
+                               200: "OK",
+                               201: "Created",
+                               202: "Accepted",
+                               203: "Non-Authoritative Information",
+                               204: "No Content",
+                               205: "Reset Content",
+                               206: "Partial Content",
+                               207: "Multi-Status",
+                               300: "Multiple Choice",
+                               301: "Moved Permanently",
+                               302: "Found",
+                               303: "See Other",
+                               304: "Not Modified",
+                               305: "Use Proxy",
+                               307: "Temporary Redirect",
+                               400: "Bad Request",
+                               401: "Unauthorized",
+                               402: "Payment Required",
+                               403: "Forbidden",
+                               404: "Not Found",
+                               405: "Method Not Allowed",
+                               406: "Not Acceptable",
+                               407: "Proxy Authentication Required",
+                               408: "Request Timeout",
+                               409: "Conflict",
+                               410: "Gone",
+                               411: "Length Required",
+                               412: "Precondition Failed",
+                               413: "Request Entity Too Large",
+                               414: "Request-URI Too Long",
+                               415: "Unsupported Media Type",
+                               416: "Requested Range Not Satisfiable",
+                               417: "Expectation Failed",
+                               422: "Unprocessable Entity",
+                               500: "Internal Server Error",
+                               501: "Not Implemented",
+                               502: "Bad Gateway",
+                               503: "Service Unavailable",
+                               504: "Gateway Timeout",
+                               505: "HTTP Version Not Supported"
+               };
+
+               function makeApi(sinon) {
+                               sinon.xhr = sinonXhr;
+
+                               sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
+                                               async: true,
+
+                                               open: function open(method, url, async, username, password) {
+                                                               this.method = method;
+                                                               this.url = url;
+                                                               this.async = typeof async == "boolean" ? async : true;
+                                                               this.username = username;
+                                                               this.password = password;
+                                                               this.responseText = null;
+                                                               this.responseXML = null;
+                                                               this.requestHeaders = {};
+                                                               this.sendFlag = false;
+
+                                                               if (FakeXMLHttpRequest.useFilters === true) {
+                                                                               var xhrArgs = arguments;
+                                                                               var defake = some(FakeXMLHttpRequest.filters, function (filter) {
+                                                                                               return filter.apply(this, xhrArgs)
+                                                                               });
+                                                                               if (defake) {
+                                                                                               return FakeXMLHttpRequest.defake(this, arguments);
+                                                                               }
+                                                               }
+                                                               this.readyStateChange(FakeXMLHttpRequest.OPENED);
+                                               },
+
+                                               readyStateChange: function readyStateChange(state) {
+                                                               this.readyState = state;
+
+                                                               if (typeof this.onreadystatechange == "function") {
+                                                                               try {
+                                                                                               this.onreadystatechange();
+                                                                               } catch (e) {
+                                                                                               sinon.logError("Fake XHR onreadystatechange handler", e);
+                                                                               }
+                                                               }
+
+                                                               this.dispatchEvent(new sinon.Event("readystatechange"));
+
+                                                               switch (this.readyState) {
+                                                                               case FakeXMLHttpRequest.DONE:
+                                                                                               this.dispatchEvent(new sinon.Event("load", false, false, this));
+                                                                                               this.dispatchEvent(new sinon.Event("loadend", false, false, this));
+                                                                                               this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
+                                                                                               if (supportsProgress) {
+                                                                                                               this.upload.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100}));
+                                                                                                               this.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100}));
+                                                                                               }
+                                                                                               break;
+                                                               }
+                                               },
+
+                                               setRequestHeader: function setRequestHeader(header, value) {
+                                                               verifyState(this);
+
+                                                               if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
+                                                                               throw new Error("Refused to set unsafe header \"" + header + "\"");
+                                                               }
+
+                                                               if (this.requestHeaders[header]) {
+                                                                               this.requestHeaders[header] += "," + value;
+                                                               } else {
+                                                                               this.requestHeaders[header] = value;
+                                                               }
+                                               },
+
+                                               // Helps testing
+                                               setResponseHeaders: function setResponseHeaders(headers) {
+                                                               verifyRequestOpened(this);
+                                                               this.responseHeaders = {};
+
+                                                               for (var header in headers) {
+                                                                               if (headers.hasOwnProperty(header)) {
+                                                                                               this.responseHeaders[header] = headers[header];
+                                                                               }
+                                                               }
+
+                                                               if (this.async) {
+                                                                               this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+                                                               } else {
+                                                                               this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
+                                                               }
+                                               },
+
+                                               // Currently treats ALL data as a DOMString (i.e. no Document)
+                                               send: function send(data) {
+                                                               verifyState(this);
+
+                                                               if (!/^(get|head)$/i.test(this.method)) {
+                                                                               var contentType = getHeader(this.requestHeaders, "Content-Type");
+                                                                               if (this.requestHeaders[contentType]) {
+                                                                                               var value = this.requestHeaders[contentType].split(";");
+                                                                                               this.requestHeaders[contentType] = value[0] + ";charset=utf-8";
+                                                                               } else if (!(data instanceof FormData)) {
+                                                                                               this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+                                                                               }
+
+                                                                               this.requestBody = data;
+                                                               }
+
+                                                               this.errorFlag = false;
+                                                               this.sendFlag = this.async;
+                                                               this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+                                                               if (typeof this.onSend == "function") {
+                                                                               this.onSend(this);
+                                                               }
+
+                                                               this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
+                                               },
+
+                                               abort: function abort() {
+                                                               this.aborted = true;
+                                                               this.responseText = null;
+                                                               this.errorFlag = true;
+                                                               this.requestHeaders = {};
+
+                                                               if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) {
+                                                                               this.readyStateChange(FakeXMLHttpRequest.DONE);
+                                                                               this.sendFlag = false;
+                                                               }
+
+                                                               this.readyState = FakeXMLHttpRequest.UNSENT;
+
+                                                               this.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+                                                               this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+                                                               if (typeof this.onerror === "function") {
+                                                                               this.onerror();
+                                                               }
+                                               },
+
+                                               getResponseHeader: function getResponseHeader(header) {
+                                                               if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                                                                               return null;
+                                                               }
+
+                                                               if (/^Set-Cookie2?$/i.test(header)) {
+                                                                               return null;
+                                                               }
+
+                                                               header = getHeader(this.responseHeaders, header);
+
+                                                               return this.responseHeaders[header] || null;
+                                               },
+
+                                               getAllResponseHeaders: function getAllResponseHeaders() {
+                                                               if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+                                                                               return "";
+                                                               }
+
+                                                               var headers = "";
+
+                                                               for (var header in this.responseHeaders) {
+                                                                               if (this.responseHeaders.hasOwnProperty(header) &&
+                                                                                               !/^Set-Cookie2?$/i.test(header)) {
+                                                                                               headers += header + ": " + this.responseHeaders[header] + "\r\n";
+                                                                               }
+                                                               }
+
+                                                               return headers;
+                                               },
+
+                                               setResponseBody: function setResponseBody(body) {
+                                                               verifyRequestSent(this);
+                                                               verifyHeadersReceived(this);
+                                                               verifyResponseBodyType(body);
+
+                                                               var chunkSize = this.chunkSize || 10;
+                                                               var index = 0;
+                                                               this.responseText = "";
+
+                                                               do {
+                                                                               if (this.async) {
+                                                                                               this.readyStateChange(FakeXMLHttpRequest.LOADING);
+                                                                               }
+
+                                                                               this.responseText += body.substring(index, index + chunkSize);
+                                                                               index += chunkSize;
+                                                               } while (index < body.length);
+
+                                                               var type = this.getResponseHeader("Content-Type");
+
+                                                               if (this.responseText &&
+                                                                               (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
+                                                                               try {
+                                                                                               this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+                                                                               } catch (e) {
+                                                                                               // Unable to parse XML - no biggie
+                                                                               }
+                                                               }
+
+                                                               this.readyStateChange(FakeXMLHttpRequest.DONE);
+                                               },
+
+                                               respond: function respond(status, headers, body) {
+                                                               this.status = typeof status == "number" ? status : 200;
+                                                               this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
+                                                               this.setResponseHeaders(headers || {});
+                                                               this.setResponseBody(body || "");
+                                               },
+
+                                               uploadProgress: function uploadProgress(progressEventRaw) {
+                                                               if (supportsProgress) {
+                                                                               this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
+                                                               }
+                                               },
+
+                                               downloadProgress: function downloadProgress(progressEventRaw) {
+                                                               if (supportsProgress) {
+                                                                               this.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
+                                                               }
+                                               },
+
+                                               uploadError: function uploadError(error) {
+                                                               if (supportsCustomEvent) {
+                                                                               this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error}));
+                                                               }
+                                               }
+                               });
+
+                               sinon.extend(FakeXMLHttpRequest, {
+                                               UNSENT: 0,
+                                               OPENED: 1,
+                                               HEADERS_RECEIVED: 2,
+                                               LOADING: 3,
+                                               DONE: 4
+                               });
+
+                               sinon.useFakeXMLHttpRequest = function () {
+                                               FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+                                                               if (sinonXhr.supportsXHR) {
+                                                                               global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest;
+                                                               }
+
+                                                               if (sinonXhr.supportsActiveX) {
+                                                                               global.ActiveXObject = sinonXhr.GlobalActiveXObject;
+                                                               }
+
+                                                               delete FakeXMLHttpRequest.restore;
+
+                                                               if (keepOnCreate !== true) {
+                                                                               delete FakeXMLHttpRequest.onCreate;
+                                                               }
+                                               };
+                                               if (sinonXhr.supportsXHR) {
+                                                               global.XMLHttpRequest = FakeXMLHttpRequest;
+                                               }
+
+                                               if (sinonXhr.supportsActiveX) {
+                                                               global.ActiveXObject = function ActiveXObject(objId) {
+                                                                               if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+                                                                                               return new FakeXMLHttpRequest();
+                                                                               }
+
+                                                                               return new sinonXhr.GlobalActiveXObject(objId);
+                                                               };
+                                               }
+
+                                               return FakeXMLHttpRequest;
+                               };
+
+                               sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./core");
+                               require("../extend");
+                               require("./event");
+                               require("../log_error");
+                               makeApi(sinon);
+                               module.exports = sinon;
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (typeof sinon === "undefined") {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+
+})(typeof global !== "undefined" ? global : this);
+
+/**
+ * @depend fake_xdomain_request.js
+ * @depend fake_xml_http_request.js
+ * @depend ../format.js
+ * @depend ../log_error.js
+ */
+/**
+ * The Sinon "server" mimics a web server that receives requests from
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
+ * both synchronously and asynchronously. To respond synchronuously, canned
+ * answers have to be provided upfront.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+               var sinon = {};
+}
+
+(function () {
+               var push = [].push;
+               function F() {}
+
+               function create(proto) {
+                               F.prototype = proto;
+                               return new F();
+               }
+
+               function responseArray(handler) {
+                               var response = handler;
+
+                               if (Object.prototype.toString.call(handler) != "[object Array]") {
+                                               response = [200, {}, handler];
+                               }
+
+                               if (typeof response[2] != "string") {
+                                               throw new TypeError("Fake server response body should be string, but was " +
+                                                                                                                               typeof response[2]);
+                               }
+
+                               return response;
+               }
+
+               var wloc = typeof window !== "undefined" ? window.location : {};
+               var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+               function matchOne(response, reqMethod, reqUrl) {
+                               var rmeth = response.method;
+                               var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
+                               var url = response.url;
+                               var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
+
+                               return matchMethod && matchUrl;
+               }
+
+               function match(response, request) {
+                               var requestUrl = request.url;
+
+                               if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+                                               requestUrl = requestUrl.replace(rCurrLoc, "");
+                               }
+
+                               if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+                                               if (typeof response.response == "function") {
+                                                               var ru = response.url;
+                                                               var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
+                                                               return response.response.apply(response, args);
+                                               }
+
+                                               return true;
+                               }
+
+                               return false;
+               }
+
+               function makeApi(sinon) {
+                               sinon.fakeServer = {
+                                               create: function () {
+                                                               var server = create(this);
+                                                               if (!sinon.xhr.supportsCORS) {
+                                                                               this.xhr = sinon.useFakeXDomainRequest();
+                                                               } else {
+                                                                               this.xhr = sinon.useFakeXMLHttpRequest();
+                                                               }
+                                                               server.requests = [];
+
+                                                               this.xhr.onCreate = function (xhrObj) {
+                                                                               server.addRequest(xhrObj);
+                                                               };
+
+                                                               return server;
+                                               },
+
+                                               addRequest: function addRequest(xhrObj) {
+                                                               var server = this;
+                                                               push.call(this.requests, xhrObj);
+
+                                                               xhrObj.onSend = function () {
+                                                                               server.handleRequest(this);
+
+                                                                               if (server.respondImmediately) {
+                                                                                               server.respond();
+                                                                               } else if (server.autoRespond && !server.responding) {
+                                                                                               setTimeout(function () {
+                                                                                                               server.responding = false;
+                                                                                                               server.respond();
+                                                                                               }, server.autoRespondAfter || 10);
+
+                                                                                               server.responding = true;
+                                                                               }
+                                                               };
+                                               },
+
+                                               getHTTPMethod: function getHTTPMethod(request) {
+                                                               if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+                                                                               var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+                                                                               return !!matches ? matches[1] : request.method;
+                                                               }
+
+                                                               return request.method;
+                                               },
+
+                                               handleRequest: function handleRequest(xhr) {
+                                                               if (xhr.async) {
+                                                                               if (!this.queue) {
+                                                                                               this.queue = [];
+                                                                               }
+
+                                                                               push.call(this.queue, xhr);
+                                                               } else {
+                                                                               this.processRequest(xhr);
+                                                               }
+                                               },
+
+                                               log: function log(response, request) {
+                                                               var str;
+
+                                                               str =  "Request:\n"  + sinon.format(request)  + "\n\n";
+                                                               str += "Response:\n" + sinon.format(response) + "\n\n";
+
+                                                               sinon.log(str);
+                                               },
+
+                                               respondWith: function respondWith(method, url, body) {
+                                                               if (arguments.length == 1 && typeof method != "function") {
+                                                                               this.response = responseArray(method);
+                                                                               return;
+                                                               }
+
+                                                               if (!this.responses) { this.responses = []; }
+
+                                                               if (arguments.length == 1) {
+                                                                               body = method;
+                                                                               url = method = null;
+                                                               }
+
+                                                               if (arguments.length == 2) {
+                                                                               body = url;
+                                                                               url = method;
+                                                                               method = null;
+                                                               }
+
+                                                               push.call(this.responses, {
+                                                                               method: method,
+                                                                               url: url,
+                                                                               response: typeof body == "function" ? body : responseArray(body)
+                                                               });
+                                               },
+
+                                               respond: function respond() {
+                                                               if (arguments.length > 0) {
+                                                                               this.respondWith.apply(this, arguments);
+                                                               }
+
+                                                               var queue = this.queue || [];
+                                                               var requests = queue.splice(0, queue.length);
+                                                               var request;
+
+                                                               while (request = requests.shift()) {
+                                                                               this.processRequest(request);
+                                                               }
+                                               },
+
+                                               processRequest: function processRequest(request) {
+                                                               try {
+                                                                               if (request.aborted) {
+                                                                                               return;
+                                                                               }
+
+                                                                               var response = this.response || [404, {}, ""];
+
+                                                                               if (this.responses) {
+                                                                                               for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
+                                                                                                               if (match.call(this, this.responses[i], request)) {
+                                                                                                                               response = this.responses[i].response;
+                                                                                                                               break;
+                                                                                                               }
+                                                                                               }
+                                                                               }
+
+                                                                               if (request.readyState != 4) {
+                                                                                               this.log(response, request);
+
+                                                                                               request.respond(response[0], response[1], response[2]);
+                                                                               }
+                                                               } catch (e) {
+                                                                               sinon.logError("Fake server request processing", e);
+                                                               }
+                                               },
+
+                                               restore: function restore() {
+                                                               return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+                                               }
+                               };
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./core");
+                               require("./fake_xdomain_request");
+                               require("./fake_xml_http_request");
+                               require("../format");
+                               makeApi(sinon);
+                               module.exports = sinon;
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else {
+                               makeApi(sinon);
+               }
+}());
+
+/**
+ * @depend fake_server.js
+ * @depend fake_timers.js
+ */
+/**
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
+ * it polls the object for completion with setInterval. Dispite the direct
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
+ * in any environment where the ajax implementation depends on setInterval or
+ * setTimeout.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function () {
+               function makeApi(sinon) {
+                               function Server() {}
+                               Server.prototype = sinon.fakeServer;
+
+                               sinon.fakeServerWithClock = new Server();
+
+                               sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
+                                               if (xhr.async) {
+                                                               if (typeof setTimeout.clock == "object") {
+                                                                               this.clock = setTimeout.clock;
+                                                               } else {
+                                                                               this.clock = sinon.useFakeTimers();
+                                                                               this.resetClock = true;
+                                                               }
+
+                                                               if (!this.longestTimeout) {
+                                                                               var clockSetTimeout = this.clock.setTimeout;
+                                                                               var clockSetInterval = this.clock.setInterval;
+                                                                               var server = this;
+
+                                                                               this.clock.setTimeout = function (fn, timeout) {
+                                                                                               server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+                                                                                               return clockSetTimeout.apply(this, arguments);
+                                                                               };
+
+                                                                               this.clock.setInterval = function (fn, timeout) {
+                                                                                               server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+                                                                                               return clockSetInterval.apply(this, arguments);
+                                                                               };
+                                                               }
+                                               }
+
+                                               return sinon.fakeServer.addRequest.call(this, xhr);
+                               };
+
+                               sinon.fakeServerWithClock.respond = function respond() {
+                                               var returnVal = sinon.fakeServer.respond.apply(this, arguments);
+
+                                               if (this.clock) {
+                                                               this.clock.tick(this.longestTimeout || 0);
+                                                               this.longestTimeout = 0;
+
+                                                               if (this.resetClock) {
+                                                                               this.clock.restore();
+                                                                               this.resetClock = false;
+                                                               }
+                                               }
+
+                                               return returnVal;
+                               };
+
+                               sinon.fakeServerWithClock.restore = function restore() {
+                                               if (this.clock) {
+                                                               this.clock.restore();
+                                               }
+
+                                               return sinon.fakeServer.restore.apply(this, arguments);
+                               };
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require) {
+                               var sinon = require("./core");
+                               require("./fake_server");
+                               require("./fake_timers");
+                               makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require);
+               } else {
+                               makeApi(sinon);
+               }
+}());
+
+/**
+ * @depend util/core.js
+ * @depend extend.js
+ * @depend collection.js
+ * @depend util/fake_timers.js
+ * @depend util/fake_server_with_clock.js
+ */
+/**
+ * Manages fake collections as well as fake utilities such as Sinon's
+ * timers and fake XHR implementation in one convenient object.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function () {
+               function makeApi(sinon) {
+                               var push = [].push;
+
+                               function exposeValue(sandbox, config, key, value) {
+                                               if (!value) {
+                                                               return;
+                                               }
+
+                                               if (config.injectInto && !(key in config.injectInto)) {
+                                                               config.injectInto[key] = value;
+                                                               sandbox.injectedKeys.push(key);
+                                               } else {
+                                                               push.call(sandbox.args, value);
+                                               }
+                               }
+
+                               function prepareSandboxFromConfig(config) {
+                                               var sandbox = sinon.create(sinon.sandbox);
+
+                                               if (config.useFakeServer) {
+                                                               if (typeof config.useFakeServer == "object") {
+                                                                               sandbox.serverPrototype = config.useFakeServer;
+                                                               }
+
+                                                               sandbox.useFakeServer();
+                                               }
+
+                                               if (config.useFakeTimers) {
+                                                               if (typeof config.useFakeTimers == "object") {
+                                                                               sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+                                                               } else {
+                                                                               sandbox.useFakeTimers();
+                                                               }
+                                               }
+
+                                               return sandbox;
+                               }
+
+                               sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
+                                               useFakeTimers: function useFakeTimers() {
+                                                               this.clock = sinon.useFakeTimers.apply(sinon, arguments);
+
+                                                               return this.add(this.clock);
+                                               },
+
+                                               serverPrototype: sinon.fakeServer,
+
+                                               useFakeServer: function useFakeServer() {
+                                                               var proto = this.serverPrototype || sinon.fakeServer;
+
+                                                               if (!proto || !proto.create) {
+                                                                               return null;
+                                                               }
+
+                                                               this.server = proto.create();
+                                                               return this.add(this.server);
+                                               },
+
+                                               inject: function (obj) {
+                                                               sinon.collection.inject.call(this, obj);
+
+                                                               if (this.clock) {
+                                                                               obj.clock = this.clock;
+                                                               }
+
+                                                               if (this.server) {
+                                                                               obj.server = this.server;
+                                                                               obj.requests = this.server.requests;
+                                                               }
+
+                                                               obj.match = sinon.match;
+
+                                                               return obj;
+                                               },
+
+                                               restore: function () {
+                                                               sinon.collection.restore.apply(this, arguments);
+                                                               this.restoreContext();
+                                               },
+
+                                               restoreContext: function () {
+                                                               if (this.injectedKeys) {
+                                                                               for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
+                                                                                               delete this.injectInto[this.injectedKeys[i]];
+                                                                               }
+                                                                               this.injectedKeys = [];
+                                                               }
+                                               },
+
+                                               create: function (config) {
+                                                               if (!config) {
+                                                                               return sinon.create(sinon.sandbox);
+                                                               }
+
+                                                               var sandbox = prepareSandboxFromConfig(config);
+                                                               sandbox.args = sandbox.args || [];
+                                                               sandbox.injectedKeys = [];
+                                                               sandbox.injectInto = config.injectInto;
+                                                               var prop, value, exposed = sandbox.inject({});
+
+                                                               if (config.properties) {
+                                                                               for (var i = 0, l = config.properties.length; i < l; i++) {
+                                                                                               prop = config.properties[i];
+                                                                                               value = exposed[prop] || prop == "sandbox" && sandbox;
+                                                                                               exposeValue(sandbox, config, prop, value);
+                                                                               }
+                                                               } else {
+                                                                               exposeValue(sandbox, config, "sandbox", value);
+                                                               }
+
+                                                               return sandbox;
+                                               },
+
+                                               match: sinon.match
+                               });
+
+                               sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
+
+                               return sinon.sandbox;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./extend");
+                               require("./util/fake_server_with_clock");
+                               require("./util/fake_timers");
+                               require("./collection");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}());
+
+/**
+ * @depend util/core.js
+ * @depend sandbox.js
+ */
+/**
+ * Test function, sandboxes fakes
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               function makeApi(sinon) {
+                               var slice = Array.prototype.slice;
+
+                               function test(callback) {
+                                               var type = typeof callback;
+
+                                               if (type != "function") {
+                                                               throw new TypeError("sinon.test needs to wrap a test function, got " + type);
+                                               }
+
+                                               function sinonSandboxedTest() {
+                                                               var config = sinon.getConfig(sinon.config);
+                                                               config.injectInto = config.injectIntoThis && this || config.injectInto;
+                                                               var sandbox = sinon.sandbox.create(config);
+                                                               var args = slice.call(arguments);
+                                                               var oldDone = args.length && args[args.length - 1];
+                                                               var exception, result;
+
+                                                               if (typeof oldDone == "function") {
+                                                                               args[args.length - 1] = function sinonDone(result) {
+                                                                                               if (result) {
+                                                                                                               sandbox.restore();
+                                                                                                               throw exception;
+                                                                                               } else {
+                                                                                                               sandbox.verifyAndRestore();
+                                                                                               }
+                                                                                               oldDone(result);
+                                                                               };
+                                                               }
+
+                                                               try {
+                                                                               result = callback.apply(this, args.concat(sandbox.args));
+                                                               } catch (e) {
+                                                                               exception = e;
+                                                               }
+
+                                                               if (typeof oldDone != "function") {
+                                                                               if (typeof exception !== "undefined") {
+                                                                                               sandbox.restore();
+                                                                                               throw exception;
+                                                                               } else {
+                                                                                               sandbox.verifyAndRestore();
+                                                                               }
+                                                               }
+
+                                                               return result;
+                                               }
+
+                                               if (callback.length) {
+                                                               return function sinonAsyncSandboxedTest(callback) {
+                                                                               return sinonSandboxedTest.apply(this, arguments);
+                                                               };
+                                               }
+
+                                               return sinonSandboxedTest;
+                               }
+
+                               test.config = {
+                                               injectIntoThis: true,
+                                               injectInto: null,
+                                               properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+                                               useFakeTimers: true,
+                                               useFakeServer: true
+                               };
+
+                               sinon.test = test;
+                               return test;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./sandbox");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (sinon) {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend test.js
+ */
+/**
+ * Test case, sandboxes all test functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+               function createTest(property, setUp, tearDown) {
+                               return function () {
+                                               if (setUp) {
+                                                               setUp.apply(this, arguments);
+                                               }
+
+                                               var exception, result;
+
+                                               try {
+                                                               result = property.apply(this, arguments);
+                                               } catch (e) {
+                                                               exception = e;
+                                               }
+
+                                               if (tearDown) {
+                                                               tearDown.apply(this, arguments);
+                                               }
+
+                                               if (exception) {
+                                                               throw exception;
+                                               }
+
+                                               return result;
+                               };
+               }
+
+               function makeApi(sinon) {
+                               function testCase(tests, prefix) {
+                                               /*jsl:ignore*/
+                                               if (!tests || typeof tests != "object") {
+                                                               throw new TypeError("sinon.testCase needs an object with test functions");
+                                               }
+                                               /*jsl:end*/
+
+                                               prefix = prefix || "test";
+                                               var rPrefix = new RegExp("^" + prefix);
+                                               var methods = {}, testName, property, method;
+                                               var setUp = tests.setUp;
+                                               var tearDown = tests.tearDown;
+
+                                               for (testName in tests) {
+                                                               if (tests.hasOwnProperty(testName)) {
+                                                                               property = tests[testName];
+
+                                                                               if (/^(setUp|tearDown)$/.test(testName)) {
+                                                                                               continue;
+                                                                               }
+
+                                                                               if (typeof property == "function" && rPrefix.test(testName)) {
+                                                                                               method = property;
+
+                                                                                               if (setUp || tearDown) {
+                                                                                                               method = createTest(property, setUp, tearDown);
+                                                                                               }
+
+                                                                                               methods[testName] = sinon.test(method);
+                                                                               } else {
+                                                                                               methods[testName] = tests[testName];
+                                                                               }
+                                                               }
+                                               }
+
+                                               return methods;
+                               }
+
+                               sinon.testCase = testCase;
+                               return testCase;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./test");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend times_in_words.js
+ * @depend util/core.js
+ * @depend match.js
+ * @depend format.js
+ */
+/**
+ * Assertions matching the test spy retrieval interface.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon, global) {
+               var slice = Array.prototype.slice;
+
+               function makeApi(sinon) {
+                               var assert;
+
+                               function verifyIsStub() {
+                                               var method;
+
+                                               for (var i = 0, l = arguments.length; i < l; ++i) {
+                                                               method = arguments[i];
+
+                                                               if (!method) {
+                                                                               assert.fail("fake is not a spy");
+                                                               }
+
+                                                               if (method.proxy) {
+                                                                               verifyIsStub(method.proxy);
+                                                               } else {
+                                                                               if (typeof method != "function") {
+                                                                                               assert.fail(method + " is not a function");
+                                                                               }
+
+                                                                               if (typeof method.getCall != "function") {
+                                                                                               assert.fail(method + " is not stubbed");
+                                                                               }
+                                                               }
+
+                                               }
+                               }
+
+                               function failAssertion(object, msg) {
+                                               object = object || global;
+                                               var failMethod = object.fail || assert.fail;
+                                               failMethod.call(object, msg);
+                               }
+
+                               function mirrorPropAsAssertion(name, method, message) {
+                                               if (arguments.length == 2) {
+                                                               message = method;
+                                                               method = name;
+                                               }
+
+                                               assert[name] = function (fake) {
+                                                               verifyIsStub(fake);
+
+                                                               var args = slice.call(arguments, 1);
+                                                               var failed = false;
+
+                                                               if (typeof method == "function") {
+                                                                               failed = !method(fake);
+                                                               } else {
+                                                                               failed = typeof fake[method] == "function" ?
+                                                                                               !fake[method].apply(fake, args) : !fake[method];
+                                                               }
+
+                                                               if (failed) {
+                                                                               failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args)));
+                                                               } else {
+                                                                               assert.pass(name);
+                                                               }
+                                               };
+                               }
+
+                               function exposedName(prefix, prop) {
+                                               return !prefix || /^fail/.test(prop) ? prop :
+                                                               prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+                               }
+
+                               assert = {
+                                               failException: "AssertError",
+
+                                               fail: function fail(message) {
+                                                               var error = new Error(message);
+                                                               error.name = this.failException || assert.failException;
+
+                                                               throw error;
+                                               },
+
+                                               pass: function pass(assertion) {},
+
+                                               callOrder: function assertCallOrder() {
+                                                               verifyIsStub.apply(null, arguments);
+                                                               var expected = "", actual = "";
+
+                                                               if (!sinon.calledInOrder(arguments)) {
+                                                                               try {
+                                                                                               expected = [].join.call(arguments, ", ");
+                                                                                               var calls = slice.call(arguments);
+                                                                                               var i = calls.length;
+                                                                                               while (i) {
+                                                                                                               if (!calls[--i].called) {
+                                                                                                                               calls.splice(i, 1);
+                                                                                                               }
+                                                                                               }
+                                                                                               actual = sinon.orderByFirstCall(calls).join(", ");
+                                                                               } catch (e) {
+                                                                                               // If this fails, we'll just fall back to the blank string
+                                                                               }
+
+                                                                               failAssertion(this, "expected " + expected + " to be " +
+                                                                                                                               "called in order but were called as " + actual);
+                                                               } else {
+                                                                               assert.pass("callOrder");
+                                                               }
+                                               },
+
+                                               callCount: function assertCallCount(method, count) {
+                                                               verifyIsStub(method);
+
+                                                               if (method.callCount != count) {
+                                                                               var msg = "expected %n to be called " + sinon.timesInWords(count) +
+                                                                                               " but was called %c%C";
+                                                                               failAssertion(this, method.printf(msg));
+                                                               } else {
+                                                                               assert.pass("callCount");
+                                                               }
+                                               },
+
+                                               expose: function expose(target, options) {
+                                                               if (!target) {
+                                                                               throw new TypeError("target is null or undefined");
+                                                               }
+
+                                                               var o = options || {};
+                                                               var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
+                                                               var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
+
+                                                               for (var method in this) {
+                                                                               if (method != "expose" && (includeFail || !/^(fail)/.test(method))) {
+                                                                                               target[exposedName(prefix, method)] = this[method];
+                                                                               }
+                                                               }
+
+                                                               return target;
+                                               },
+
+                                               match: function match(actual, expectation) {
+                                                               var matcher = sinon.match(expectation);
+                                                               if (matcher.test(actual)) {
+                                                                               assert.pass("match");
+                                                               } else {
+                                                                               var formatted = [
+                                                                                               "expected value to match",
+                                                                                               "    expected = " + sinon.format(expectation),
+                                                                                               "    actual = " + sinon.format(actual)
+                                                                               ]
+                                                                               failAssertion(this, formatted.join("\n"));
+                                                               }
+                                               }
+                               };
+
+                               mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+                               mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
+                                                                                                               "expected %n to not have been called but was called %c%C");
+                               mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+                               mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+                               mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+                               mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+                               mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
+                               mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
+                               mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
+                               mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
+                               mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
+                               mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
+                               mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
+                               mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
+                               mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
+                               mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+                               mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
+                               mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+                               mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+                               sinon.assert = assert;
+                               return assert;
+               }
+
+               var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+               var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+               function loadDependencies(require, exports, module) {
+                               var sinon = require("./util/core");
+                               require("./match");
+                               require("./format");
+                               module.exports = makeApi(sinon);
+               }
+
+               if (isAMD) {
+                               define(loadDependencies);
+               } else if (isNode) {
+                               loadDependencies(require, module.exports, module);
+               } else if (!sinon) {
+                               return;
+               } else {
+                               makeApi(sinon);
+               }
+
+}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
+
+       return sinon;
+}));
index 478fed007b7021dd98b81976d5ed0fbf4af3cc77..d7cd8e606e2af3c9ad7b0ef6bb377ea96fe45952 100644 (file)
@@ -59,8 +59,10 @@ Tween.propHooks = {
                get: function( tween ) {
                        var result;
 
-                       if ( tween.elem[ tween.prop ] != null &&
-                               (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
+                       // Use a property on the element directly when it is not a DOM element,
+                       // or when there is no matching style property that exists.
+                       if ( tween.elem.nodeType !== 1 ||
+                               tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
                                return tween.elem[ tween.prop ];
                        }
 
@@ -78,7 +80,7 @@ Tween.propHooks = {
                        // Use .style if available and use plain properties where available.
                        if ( jQuery.fx.step[ tween.prop ] ) {
                                jQuery.fx.step[ tween.prop ]( tween );
-                       } else if ( tween.elem.style &&
+                       } else if ( tween.elem.nodeType === 1 &&
                                ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
                                        jQuery.cssHooks[ tween.prop ] ) ) {
                                jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
index 1b2dd185baa5f7a8efa10acccc8fbf7df4a8d003..5717918bcd79d3fab5f6c54d5145afde061f85e9 100644 (file)
@@ -154,7 +154,8 @@ jQuery.extend({
        expr: {
                attrHandle: {},
                match: {
-                       bool: /^(?:checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$/i,
+                       bool: new RegExp( "^(?:checked|selected|async|autofocus|autoplay|controls|defer" +
+                               "|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped)$", "i" ),
                        needsContext: /^[\x20\t\r\n\f]*[>+~]/
                }
        }
index 468956d4dfb30c5e2b85e38875778d6a3818cab0..e59d9db3259f8e91bb78ca7c753bcf1bc8821784 100644 (file)
@@ -285,7 +285,8 @@ this.loadTests = function() {
                        "unit/ajax.js",
                        "unit/effects.js",
                        "unit/offset.js",
-                       "unit/dimensions.js"
+                       "unit/dimensions.js",
+                       "unit/tween.js"
                ];
 
                // Ensure load order (to preserve test numbers)
index d8ccdaa454ee57c9ac9c15385daacb9c6f7de516..0285176d3d662ceffd9ae5fcdc54b083545d4edc 100644 (file)
@@ -13,9 +13,9 @@
        <script src="data/jquery-1.9.1.js"></script>
 
        <script src="../external/qunit/qunit.js"></script>
+       <script src="../external/sinon/sinon-1.14.1.js"></script>
        <script src="../external/npo/npo.js"></script>
        <script src="../external/requirejs/require.js"></script>
-       <script src="../external/sinon/fake_timers.js"></script>
        <!-- See testinit for the list of tests -->
        <script src="data/testinit.js"></script>
 
index 571fda0316d30fe89bb98df71d39bfe9d7fbb5b5..7aff2242ab4e2c1e6fc478a3c055cc29423c81d7 100644 (file)
@@ -10,13 +10,15 @@ var oldRaf = window.requestAnimationFrame;
 module("effects", {
        setup: function() {
                window.requestAnimationFrame = null;
-               this.clock = sinon.useFakeTimers( 505877050 );
+               this.sandbox = sinon.sandbox.create();
+               this.clock = this.sandbox.useFakeTimers( 505877050 );
                this._oldInterval = jQuery.fx.interval;
+               jQuery.fx.step = {};
                jQuery.fx.interval = 10;
                jQuery.now = Date.now;
        },
        teardown: function() {
-               this.clock.restore();
+               this.sandbox.restore();
                jQuery.now = Date.now;
                jQuery.fx.stop();
                jQuery.fx.interval = this._oldInterval;
diff --git a/test/unit/tween.js b/test/unit/tween.js
new file mode 100644 (file)
index 0000000..8b40d97
--- /dev/null
@@ -0,0 +1,298 @@
+( function() {
+
+// Can't test what ain't there
+if ( !jQuery.fx ) {
+       return;
+}
+
+var oldRaf = window.requestAnimationFrame;
+
+module( "tween", {
+       setup: function() {
+               window.requestAnimationFrame = null;
+               this.sandbox = sinon.sandbox.create();
+               this.clock = this.sandbox.useFakeTimers( 505877050 );
+               this._oldInterval = jQuery.fx.interval;
+               jQuery.fx.step = {};
+               jQuery.fx.interval = 10;
+               jQuery.now = Date.now;
+       },
+       teardown: function() {
+               this.sandbox.restore();
+               jQuery.now = Date.now;
+               jQuery.fx.stop();
+               jQuery.fx.interval = this._oldInterval;
+               window.requestAnimationFrame = oldRaf;
+               return moduleTeardown.apply( this, arguments );
+       }
+} );
+
+test( "jQuery.Tween - Default propHooks on plain objects", function() {
+       expect( 8 );
+       var propHooks, defaultHook, testObject, fakeTween, stepSpy;
+
+       propHooks = jQuery.Tween.propHooks;
+       equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" );
+
+       defaultHook = propHooks._default;
+       ok( defaultHook, "_default propHook exists" );
+
+       testObject = { test: 0 };
+       fakeTween = { elem: testObject, prop: "test", now: 10, unit: "px" };
+
+       equal( defaultHook.get( fakeTween ), 0, "Can get property of object" );
+
+       fakeTween.prop = "testMissing";
+       equal( defaultHook.get( fakeTween ), undefined, "Can get missing property on object" );
+
+       defaultHook.set( fakeTween );
+       equal( testObject.testMissing, 10, "Sets missing value properly on plain object" );
+
+       fakeTween.prop = "opacity";
+       defaultHook.set( fakeTween );
+       equal( testObject.opacity, 10, "Correctly set opacity on plain object" );
+
+       fakeTween.prop = "test";
+       stepSpy = jQuery.fx.step.test = this.sandbox.spy();
+
+       defaultHook.set( fakeTween );
+       ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" );
+       equal( testObject.test, 0, "Because step didn't set, value is unchanged" );
+} );
+
+test( "jQuery.Tween - Default propHooks on elements", function() {
+       expect( 19 );
+       var propHooks, defaultHook, testElement, fakeTween, cssStub, styleStub, stepSpy;
+
+       propHooks = jQuery.Tween.propHooks;
+       equal( typeof propHooks, "object", "jQuery.Tween.propHooks exists" );
+
+       defaultHook = propHooks._default;
+       ok( defaultHook, "_default propHook exists" );
+
+       testElement = jQuery( "<div>" )[ 0 ];
+       fakeTween = { elem: testElement, prop: "height", now: 10, unit: "px" };
+
+       cssStub = this.sandbox.stub( jQuery, "css" ).returns( 10 );
+
+       equal( defaultHook.get( fakeTween ), 10, "Gets expected style value" );
+       ok( cssStub.calledWith( testElement, "height", "" ), "Calls jQuery.css correctly" );
+
+       fakeTween.prop = "testOpti";
+       testElement.testOpti = 15;
+       cssStub.reset();
+
+       equal( defaultHook.get( fakeTween ), 15, "Gets expected value not defined on style" );
+       equal( cssStub.callCount, 0, "Did not call jQuery.css" );
+
+       fakeTween.prop = "testMissing";
+       equal( defaultHook.get( fakeTween ), 10, "Can get missing property on element" );
+       ok( cssStub.calledWith( testElement, "testMissing", "" ), "...using jQuery.css" );
+
+       cssStub.returns( "" );
+       equal( defaultHook.get( fakeTween ), 0, "Uses 0 for empty string" );
+
+       cssStub.returns( "auto" );
+       equal( defaultHook.get( fakeTween ), 0, "Uses 0 for 'auto'" );
+
+       cssStub.returns( null );
+       equal( defaultHook.get( fakeTween ), 0, "Uses 0 for null" );
+
+       cssStub.returns( undefined );
+       equal( defaultHook.get( fakeTween ), 0, "Uses 0 for undefined" );
+
+       cssStub.reset();
+
+       // Setters
+       styleStub = this.sandbox.stub( jQuery, "style" );
+       fakeTween.prop = "height";
+
+       defaultHook.set( fakeTween );
+       ok( styleStub.calledWith( testElement, "height", "10px" ),
+               "Calls jQuery.style with elem, prop, now+unit" );
+
+       styleStub.reset();
+       fakeTween.prop = "testMissing";
+
+       defaultHook.set( fakeTween );
+       equal( styleStub.callCount, 0, "Did not call jQuery.style for non css property" );
+       equal( testElement.testMissing, 10, "Instead, set value on element directly" );
+
+       jQuery.cssHooks.testMissing = jQuery.noop;
+       fakeTween.now = 11;
+
+       defaultHook.set( fakeTween );
+       delete jQuery.cssHooks.testMissing;
+
+       ok( styleStub.calledWith( testElement, "testMissing", "11px" ),
+               "Presence of cssHooks causes jQuery.style with elem, prop, now+unit" );
+       equal( testElement.testMissing, 10, "And value was unchanged" );
+
+       stepSpy = jQuery.fx.step.test = this.sandbox.spy();
+       styleStub.reset();
+
+       fakeTween.prop = "test";
+       defaultHook.set( fakeTween );
+       ok( stepSpy.calledWith( fakeTween ), "Step function called with Tween" );
+       equal( styleStub.callCount, 0, "Did not call jQuery.style" );
+} );
+
+test( "jQuery.Tween - Plain Object", function() {
+       expect( 13 );
+       var testObject = { test: 100 },
+               testOptions = { duration: 100 },
+               tween, easingSpy;
+
+       tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" );
+       equal( tween.elem, testObject, "Sets .element" );
+       equal( tween.options, testOptions, "sets .options" );
+       equal( tween.prop, "test", "sets .prop" );
+       equal( tween.end, 0, "sets .end" );
+
+       equal( tween.easing, "linear", "sets .easing when provided" );
+
+       equal( tween.start, 100, "Reads .start value during construction" );
+       equal( tween.now, 100, "Reads .now value during construction" );
+
+       easingSpy = this.sandbox.spy( jQuery.easing, "linear" );
+
+       equal( tween.run( 0.1 ), tween, ".run() returns this" );
+
+       equal( tween.now, 90, "Calculated tween" );
+
+       ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ),
+               "...using jQuery.easing.linear with back-compat arguments" );
+       equal( testObject.test, 90, "Set value" );
+
+       tween.run( 1 );
+       equal( testObject.test, 0, "Checking another value" );
+
+       tween.run( 0 );
+       equal( testObject.test, 100, "Can even go back in time" );
+} );
+
+test( "jQuery.Tween - Element", function() {
+       expect( 15 );
+       var testElement = jQuery( "<div>" ).css( "height", 100 )[ 0 ],
+               testOptions = { duration: 100 },
+               tween, easingSpy, eased;
+
+       tween = jQuery.Tween( testElement, testOptions, "height", 0 );
+       equal( tween.elem, testElement, "Sets .element" );
+       equal( tween.options, testOptions, "sets .options" );
+       equal( tween.prop, "height", "sets .prop" );
+       equal( tween.end, 0, "sets .end" );
+
+       equal( tween.easing, jQuery.easing._default, "sets .easing to default when not provided" );
+       equal( tween.unit, "px", "sets .unit to px when not provided" );
+
+       equal( tween.start, 100, "Reads .start value during construction" );
+       equal( tween.now, 100, "Reads .now value during construction" );
+
+       easingSpy = this.sandbox.spy( jQuery.easing, "swing" );
+
+       equal( tween.run( 0.1 ), tween, ".run() returns this" );
+       equal( tween.pos, jQuery.easing.swing( 0.1 ), "set .pos" );
+       eased = 100 - ( jQuery.easing.swing( 0.1 ) * 100 );
+       equal( tween.now, eased, "Calculated tween" );
+
+       ok( easingSpy.calledWith( 0.1, 0.1 * testOptions.duration, 0, 1, testOptions.duration ),
+               "...using jQuery.easing.linear with back-compat arguments" );
+       equal( parseFloat( testElement.style.height ).toFixed( 5 ), eased.toFixed( 5 ), "Set value" );
+
+       tween.run( 1 );
+       equal( testElement.style.height, "0px", "Checking another value" );
+
+       tween.run( 0 );
+       equal( testElement.style.height, "100px", "Can even go back in time" );
+} );
+
+test( "jQuery.Tween - No duration", function() {
+       expect( 3 );
+
+       var testObject = { test: 100 },
+               testOptions = { duration: 0 },
+               tween, easingSpy;
+
+       tween = jQuery.Tween( testObject, testOptions, "test", 0 );
+       easingSpy = this.sandbox.spy( jQuery.easing, "swing" );
+       tween.run( 0.5 );
+
+       equal( tween.pos, 0.5, "set .pos correctly" );
+       equal( testObject.test, 50, "set value on object correctly" );
+       equal( easingSpy.callCount, 0, "didn't ease the value" );
+} );
+
+test( "jQuery.Tween - step function option", function() {
+       expect( 4 );
+
+       var testObject = { test: 100 },
+               testOptions = { duration: 100, step: this.sandbox.spy() },
+               tween, propHookSpy;
+
+       propHookSpy = this.sandbox.spy( jQuery.Tween.propHooks._default, "set" );
+
+       tween = jQuery.Tween( testObject, testOptions, "test", 0, "linear" );
+       equal( testOptions.step.callCount, 0, "didn't call step on create" );
+
+       tween.run( 0.5 );
+       ok( testOptions.step.calledOn( testObject ),
+               "Called step function in context of animated object" );
+       ok( testOptions.step.calledWith( 50, tween ), "Called step function with correct parameters" );
+
+       ok( testOptions.step.calledBefore( propHookSpy ),
+               "Called step function before calling propHook.set" );
+
+} );
+
+test( "jQuery.Tween - custom propHooks", function() {
+       expect( 3 );
+
+       var testObject = {},
+               testOptions = { duration: 100, step: this.sandbox.spy() },
+               propHook = {
+                       get: sinon.stub().returns( 100 ),
+                       set: sinon.stub()
+               },
+               tween;
+
+       jQuery.Tween.propHooks.testHooked = propHook;
+
+       tween = jQuery.Tween( testObject, testOptions, "testHooked", 0, "linear" );
+       ok( propHook.get.calledWith( tween ), "called propHook.get on create" );
+       equal( tween.now, 100, "Used return value from propHook.get" );
+
+       tween.run( 0.5 );
+       ok( propHook.set.calledWith( tween ), "Called propHook.set function with correct parameters" );
+
+       delete jQuery.Tween.propHooks.testHooked;
+} );
+
+test( "jQuery.Tween - custom propHooks - advanced values", function() {
+       expect( 5 );
+
+       var testObject = {},
+               testOptions = { duration: 100, step: this.sandbox.spy() },
+               propHook = {
+                       get: sinon.stub().returns( [ 0, 0 ] ),
+                       set: sinon.spy()
+               },
+               tween;
+
+       jQuery.Tween.propHooks.testHooked = propHook;
+
+       tween = jQuery.Tween( testObject, testOptions, "testHooked", [ 1, 1 ], "linear" );
+       ok( propHook.get.calledWith( tween ), "called propHook.get on create" );
+       deepEqual( tween.start, [ 0, 0 ], "Used return value from get" );
+
+       tween.run( 0.5 );
+
+       // Some day this NaN assumption might change - perhaps add a "calc" helper to the hooks?
+       ok( isNaN( tween.now ), "Used return value from propHook.get" );
+       equal( tween.pos, 0.5, "But the eased percent is still avaliable" );
+       ok( propHook.set.calledWith( tween ), "Called propHook.set function with correct parameters" );
+
+       delete jQuery.Tween.propHooks.testHooked;
+} );
+
+} )();