text: /**
   * Sinon.JS 1.10.3, 2014/07/11
   *
   * @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.
   */
  
  /*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
   */
  
  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;
  }
  