[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/resources/lib/sinonjs/ -> sinon-1.10.3.js (source)

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


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1