text: /*!
   * https://github.com/es-shims/es5-shim
   * @license es5-shim Copyright 2009-2014 by contributors, MIT License
   * see https://github.com/es-shims/es5-shim/blob/master/LICENSE
   */
  
  // vim: ts=4 sts=4 sw=4 expandtab
  
  //Add semicolon to prevent IIFE from being passed as argument to concated code.
  ;
  
  // UMD (Universal Module Definition)
  // see https://github.com/umdjs/umd/blob/master/returnExports.js
  (function (root, factory) {
      if (typeof define === 'function' && define.amd) {
          // AMD. Register as an anonymous module.
          define(factory);
      } else if (typeof exports === 'object') {
          // Node. Does not work with strict CommonJS, but
          // only CommonJS-like enviroments that support module.exports,
          // like Node.
          module.exports = factory();
      } else {
          // Browser globals (root is window)
          root.returnExports = factory();
    }
  }(this, function () {
  
  /**
   * Brings an environment as close to ECMAScript 5 compliance
   * as is possible with the facilities of erstwhile engines.
   *
   * Annotated ES5: http://es5.github.com/ (specific links below)
   * ES5 Spec: http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
   * Required reading: http://javascriptweblog.wordpress.com/2011/12/05/extending-javascript-natives/
   */
  
  //
  // Function
  // ========
  //
  
  // ES-5 15.3.4.5
  // http://es5.github.com/#x15.3.4.5
  
  function Empty() {}
  
  if (!Function.prototype.bind) {
      Function.prototype.bind = function bind(that) { // .length is 1
          // 1. Let Target be the this value.
          var target = this;
          // 2. If IsCallable(Target) is false, throw a TypeError exception.
          if (typeof target != "function") {
              throw new TypeError("Function.prototype.bind called on incompatible " + target);
          }
          // 3. Let A be a new (possibly empty) internal list of all of the
          //   argument values provided after thisArg (arg1, arg2 etc), in order.
          // XXX slicedArgs will stand in for "A" if used
          var args = _Array_slice_.call(arguments, 1); // for normal call
          // 4. Let F be a new native ECMAScript object.
          // 11. Set the [[Prototype]] internal property of F to the standard
          //   built-in Function prototype object as specified in 15.3.3.1.
          // 12. Set the [[Call]] internal property of F as described in
          //   15.3.4.5.1.
          // 13. Set the [[Construct]] internal property of F as described in
          //   15.3.4.5.2.
          // 14. Set the [[HasInstance]] internal property of F as described in
          //   15.3.4.5.3.
          var binder = function () {
  
              if (this instanceof bound) {
                  // 15.3.4.5.2 [[Construct]]
                  // When the [[Construct]] internal method of a function object,
                  // F that was created using the bind function is called with a
                  // list of arguments ExtraArgs, the following steps are taken:
                  // 1. Let target be the value of F's [[TargetFunction]]
                  //   internal property.
                  // 2. If target has no [[Construct]] internal method, a
                  //   TypeError exception is thrown.
                  // 3. Let boundArgs be the value of F's [[BoundArgs]] internal
                  //   property.
                  // 4. Let args be a new list containing the same values as the
                  //   list boundArgs in the same order followed by the same
                  //   values as the list ExtraArgs in the same order.
                  // 5. Return the result of calling the [[Construct]] internal
                  //   method of target providing args as the arguments.
  
                  var result = target.apply(
                      this,
                      args.concat(_Array_slice_.call(arguments))
                  );
                  if (Object(result) === result) {
                      return result;
                  }
                  return this;
  
              } else {
                  // 15.3.4.5.1 [[Call]]
                  // When the [[Call]] internal method of a function object, F,
                  // which was created using the bind function is called with a
                  // this value and a list of arguments ExtraArgs, the following
                  // steps are taken:
                  // 1. Let boundArgs be the value of F's [[BoundArgs]] internal
                  //   property.
                  // 2. Let boundThis be the value of F's [[BoundThis]] internal
                  //   property.
                  // 3. Let target be the value of F's [[TargetFunction]] internal
                  //   property.
                  // 4. Let args be a new list containing the same values as the
                  //   list boundArgs in the same order followed by the same
                  //   values as the list ExtraArgs in the same order.
                  // 5. Return the result of calling the [[Call]] internal method
                  //   of target providing boundThis as the this value and
                  //   providing args as the arguments.
  
                  // equiv: target.call(this, ...boundArgs, ...args)
                  return target.apply(
                      that,
                      args.concat(_Array_slice_.call(arguments))
                  );
  
              }
  
          };
  
          // 15. If the [[Class]] internal property of Target is "Function", then
          //     a. Let L be the length property of Target minus the length of A.
          //     b. Set the length own property of F to either 0 or L, whichever is
          //       larger.
          // 16. Else set the length own property of F to 0.
  
          var boundLength = Math.max(0, target.length - args.length);
  
          // 17. Set the attributes of the length own property of F to the values
          //   specified in 15.3.5.1.
          var boundArgs = [];
          for (var i = 0; i < boundLength; i++) {
              boundArgs.push("$" + i);
          }
  
          // XXX Build a dynamic function with desired amount of arguments is the only 
          // way to set the length property of a function. 
          // In environments where Content Security Policies enabled (Chrome extensions, 
          // for ex.) all use of eval or Function costructor throws an exception. 
          // However in all of these environments Function.prototype.bind exists 
          // and so this code will never be executed.
          var bound = Function("binder", "return function(" + boundArgs.join(",") + "){return binder.apply(this,arguments)}")(binder);
  
          if (target.prototype) {
              Empty.prototype = target.prototype;
              bound.prototype = new Empty();
              // Clean up dangling references.
              Empty.prototype = null;
          }
  
          // TODO
          // 18. Set the [[Extensible]] internal property of F to true.
  
          // TODO
          // 19. Let thrower be the [[ThrowTypeError]] function Object (13.2.3).
          // 20. Call the [[DefineOwnProperty]] internal method of F with
          //   arguments "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]:
          //   thrower, [[Enumerable]]: false, [[Configurable]]: false}, and
          //   false.
          // 21. Call the [[DefineOwnProperty]] internal method of F with
          //   arguments "arguments", PropertyDescriptor {[[Get]]: thrower,
          //   [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: false},
          //   and false.
  
          // TODO
          // NOTE Function objects created using Function.prototype.bind do not
          // have a prototype property or the [[Code]], [[FormalParameters]], and
          // [[Scope]] internal properties.
          // XXX can't delete prototype in pure-js.
  
          // 22. Return F.
          return bound;
      };
  }
  
  // Shortcut to an often accessed properties, in order to avoid multiple
  // dereference that costs universally.
  // _Please note: Shortcuts are defined after `Function.prototype.bind` as we
  // us it in defining shortcuts.
  var call = Function.prototype.call;
  var prototypeOfArray = Array.prototype;
  var prototypeOfObject = Object.prototype;
  var _Array_slice_ = prototypeOfArray.slice;
  // Having a toString local variable name breaks in Opera so use _toString.
  var _toString = call.bind(prototypeOfObject.toString);
  var owns = call.bind(prototypeOfObject.hasOwnProperty);
  
  // If JS engine supports accessors creating shortcuts.
  var defineGetter;
  var defineSetter;
  var lookupGetter;
  var lookupSetter;
  var supportsAccessors;
  if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) {
      defineGetter = call.bind(prototypeOfObject.__defineGetter__);
      defineSetter = call.bind(prototypeOfObject.__defineSetter__);
      lookupGetter = call.bind(prototypeOfObject.__lookupGetter__);
      lookupSetter = call.bind(prototypeOfObject.__lookupSetter__);
  }
  
  //
  // Array
  // =====
  //
  
  // ES5 15.4.4.12
  // http://es5.github.com/#x15.4.4.12
  // Default value for second param
  // [bugfix, ielt9, old browsers]
  // IE < 9 bug: [1,2].splice(0).join("") == "" but should be "12"
  if ([1,2].splice(0).length != 2) {
      var array_splice = Array.prototype.splice;
      var array_push = Array.prototype.push;
      var array_unshift = Array.prototype.unshift;
  
      if (function() { // test IE < 9 to splice bug - see issue #138
          function makeArray(l) {
              var a = [];
              while (l--) {
                  a.unshift(l)
              }
              return a
          }
  
          var array = []
              , lengthBefore
          ;
  
          array.splice.bind(array, 0, 0).apply(null, makeArray(20));
          array.splice.bind(array, 0, 0).apply(null, makeArray(26));
  
          lengthBefore = array.length; //20
          array.splice(5, 0, "XXX"); // add one element
  
          if (lengthBefore + 1 == array.length) {
              return true;// has right splice implementation without bugs
          }
          // else {
          //    IE8 bug
          // }
      }()) {//IE 6/7
          Array.prototype.splice = function(start, deleteCount) {
              if (!arguments.length) {
                  return [];
              } else {
                  return array_splice.apply(this, [
                      start === void 0 ? 0 : start,
                      deleteCount === void 0 ? (this.length - start) : deleteCount
                  ].concat(_Array_slice_.call(arguments, 2)))
              }
          };
      }
      else {//IE8
          Array.prototype.splice = function(start, deleteCount) {
              var result
                  , args = _Array_slice_.call(arguments, 2)
                  , addElementsCount = args.length
              ;
  
              if (!arguments.length) {
                  return [];
              }
  
              if (start === void 0) { // default
                  start = 0;
              }
              if (deleteCount === void 0) { // default
                  deleteCount = this.length - start;
              }
  
              if (addElementsCount > 0) {
                  if (deleteCount <= 0) {
                      if (start == this.length) { // tiny optimisation #1
                          array_push.apply(this, args);
                          return [];
                      }
  
                      if (start == 0) { // tiny optimisation #2
                          array_unshift.apply(this, args);
                          return [];
                      }
                  }
  
                  // Array.prototype.splice implementation
                  result = _Array_slice_.call(this, start, start + deleteCount);// delete part
                  args.push.apply(args, _Array_slice_.call(this, start + deleteCount, this.length));// right part
                  args.unshift.apply(args, _Array_slice_.call(this, 0, start));// left part
  
                  // delete all items from this array and replace it to 'left part' + _Array_slice_.call(arguments, 2) + 'right part'
                  args.unshift(0, this.length);
  
                  array_splice.apply(this, args);
  
                  return result;
              }
  
              return array_splice.call(this, start, deleteCount);
          }
  
      }
  }
  
  // ES5 15.4.4.12
  // http://es5.github.com/#x15.4.4.13
  // Return len+argCount.
  // [bugfix, ielt8]
  // IE < 8 bug: [].unshift(0) == undefined but should be "1"
  if ([].unshift(0) != 1) {
      var array_unshift = Array.prototype.unshift;
      Array.prototype.unshift = function() {
          array_unshift.apply(this, arguments);
          return this.length;
      };
  }
  
  // ES5 15.4.3.2
  // http://es5.github.com/#x15.4.3.2
  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/isArray
  if (!Array.isArray) {
      Array.isArray = function isArray(obj) {
          return _toString(obj) == "[object Array]";
      };
  }
  
  // The IsCallable() check in the Array functions
  // has been replaced with a strict check on the
  // internal class of the object to trap cases where
  // the provided function was actually a regular
  // expression literal, which in V8 and
  // JavaScriptCore is a typeof "function".  Only in
  // V8 are regular expression literals permitted as
  // reduce parameters, so it is desirable in the
  // general case for the shim to match the more
  // strict and common behavior of rejecting regular
  // expressions.
  
  // ES5 15.4.4.18
  // http://es5.github.com/#x15.4.4.18
  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/array/forEach
  
  
  // Check failure of by-index access of string characters (IE < 9)
  // and failure of `0 in boxedString` (Rhino)
  var boxedString = Object("a");
  var splitString = boxedString[0] != "a" || !(0 in boxedString);
  
  var properlyBoxesContext = function properlyBoxed(method) {
      // Check node 0.6.21 bug where third parameter is not boxed
      var properlyBoxes = true;
      if (method) {
          method.call('foo', function (item, index, context) {
              if (typeof context !== 'object') { properlyBoxes = false; }
          });
      }
      return !!method && properlyBoxes;
  };
  
  if (!Array.prototype.forEach || !properlyBoxesContext(Array.prototype.forEach)) {
      Array.prototype.forEach = function forEach(fun /*, thisp*/) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  object,
              thisp = arguments[1],
              i = -1,
              length = self.length >>> 0;
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(); // TODO message
          }
  
          while (++i < length) {
              if (i in self) {
                  // Invoke the callback function with call, passing arguments:
                  // context, property value, property key, thisArg object
                  // context
                  fun.call(thisp, self[i], i, object);
              }
          }
      };
  }
  
  // ES5 15.4.4.19
  // http://es5.github.com/#x15.4.4.19
  // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
  if (!Array.prototype.map || !properlyBoxesContext(Array.prototype.map)) {
      Array.prototype.map = function map(fun /*, thisp*/) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  object,
              length = self.length >>> 0,
              result = Array(length),
              thisp = arguments[1];
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(fun + " is not a function");
          }
  
          for (var i = 0; i < length; i++) {
              if (i in self)
                  result[i] = fun.call(thisp, self[i], i, object);
          }
          return result;
      };
  }
  
  // ES5 15.4.4.20
  // http://es5.github.com/#x15.4.4.20
  // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
  if (!Array.prototype.filter || !properlyBoxesContext(Array.prototype.filter)) {
      Array.prototype.filter = function filter(fun /*, thisp */) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                      object,
              length = self.length >>> 0,
              result = [],
              value,
              thisp = arguments[1];
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(fun + " is not a function");
          }
  
          for (var i = 0; i < length; i++) {
              if (i in self) {
                  value = self[i];
                  if (fun.call(thisp, value, i, object)) {
                      result.push(value);
                  }
              }
          }
          return result;
      };
  }
  
  // ES5 15.4.4.16
  // http://es5.github.com/#x15.4.4.16
  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
  if (!Array.prototype.every || !properlyBoxesContext(Array.prototype.every)) {
      Array.prototype.every = function every(fun /*, thisp */) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  object,
              length = self.length >>> 0,
              thisp = arguments[1];
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(fun + " is not a function");
          }
  
          for (var i = 0; i < length; i++) {
              if (i in self && !fun.call(thisp, self[i], i, object)) {
                  return false;
              }
          }
          return true;
      };
  }
  
  // ES5 15.4.4.17
  // http://es5.github.com/#x15.4.4.17
  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
  if (!Array.prototype.some || !properlyBoxesContext(Array.prototype.some)) {
      Array.prototype.some = function some(fun /*, thisp */) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  object,
              length = self.length >>> 0,
              thisp = arguments[1];
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(fun + " is not a function");
          }
  
          for (var i = 0; i < length; i++) {
              if (i in self && fun.call(thisp, self[i], i, object)) {
                  return true;
              }
          }
          return false;
      };
  }
  
  // ES5 15.4.4.21
  // http://es5.github.com/#x15.4.4.21
  // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduce
  if (!Array.prototype.reduce) {
      Array.prototype.reduce = function reduce(fun /*, initial*/) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  object,
              length = self.length >>> 0;
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(fun + " is not a function");
          }
  
          // no value to return if no initial value and an empty array
          if (!length && arguments.length == 1) {
              throw new TypeError("reduce of empty array with no initial value");
          }
  
          var i = 0;
          var result;
          if (arguments.length >= 2) {
              result = arguments[1];
          } else {
              do {
                  if (i in self) {
                      result = self[i++];
                      break;
                  }
  
                  // if array contains no values, no initial value to return
                  if (++i >= length) {
                      throw new TypeError("reduce of empty array with no initial value");
                  }
              } while (true);
          }
  
          for (; i < length; i++) {
              if (i in self) {
                  result = fun.call(void 0, result, self[i], i, object);
              }
          }
  
          return result;
      };
  }
  
  // ES5 15.4.4.22
  // http://es5.github.com/#x15.4.4.22
  // https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/reduceRight
  if (!Array.prototype.reduceRight) {
      Array.prototype.reduceRight = function reduceRight(fun /*, initial*/) {
          var object = toObject(this),
              self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  object,
              length = self.length >>> 0;
  
          // If no callback function or if callback is not a callable function
          if (_toString(fun) != "[object Function]") {
              throw new TypeError(fun + " is not a function");
          }
  
          // no value to return if no initial value, empty array
          if (!length && arguments.length == 1) {
              throw new TypeError("reduceRight of empty array with no initial value");
          }
  
          var result, i = length - 1;
          if (arguments.length >= 2) {
              result = arguments[1];
          } else {
              do {
                  if (i in self) {
                      result = self[i--];
                      break;
                  }
  
                  // if array contains no values, no initial value to return
                  if (--i < 0) {
                      throw new TypeError("reduceRight of empty array with no initial value");
                  }
              } while (true);
          }
  
          if (i < 0) {
              return result;
          }
  
          do {
              if (i in this) {
                  result = fun.call(void 0, result, self[i], i, object);
              }
          } while (i--);
  
          return result;
      };
  }
  
  // ES5 15.4.4.14
  // http://es5.github.com/#x15.4.4.14
  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
  if (!Array.prototype.indexOf || ([0, 1].indexOf(1, 2) != -1)) {
      Array.prototype.indexOf = function indexOf(sought /*, fromIndex */ ) {
          var self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  toObject(this),
              length = self.length >>> 0;
  
          if (!length) {
              return -1;
          }
  
          var i = 0;
          if (arguments.length > 1) {
              i = toInteger(arguments[1]);
          }
  
          // handle negative indices
          i = i >= 0 ? i : Math.max(0, length + i);
          for (; i < length; i++) {
              if (i in self && self[i] === sought) {
                  return i;
              }
          }
          return -1;
      };
  }
  
  // ES5 15.4.4.15
  // http://es5.github.com/#x15.4.4.15
  // https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
  if (!Array.prototype.lastIndexOf || ([0, 1].lastIndexOf(0, -3) != -1)) {
      Array.prototype.lastIndexOf = function lastIndexOf(sought /*, fromIndex */) {
          var self = splitString && _toString(this) == "[object String]" ?
                  this.split("") :
                  toObject(this),
              length = self.length >>> 0;
  
          if (!length) {
              return -1;
          }
          var i = length - 1;
          if (arguments.length > 1) {
              i = Math.min(i, toInteger(arguments[1]));
          }
          // handle negative indices
          i = i >= 0 ? i : length - Math.abs(i);
          for (; i >= 0; i--) {
              if (i in self && sought === self[i]) {
                  return i;
              }
          }
          return -1;
      };
  }
  
  //
  // Object
  // ======
  //
  
  // ES5 15.2.3.14
  // http://es5.github.com/#x15.2.3.14
  if (!Object.keys) {
      // http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
      var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
          hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
          dontEnums = [
              "toString",
              "toLocaleString",
              "valueOf",
              "hasOwnProperty",
              "isPrototypeOf",
              "propertyIsEnumerable",
              "constructor"
          ],
          dontEnumsLength = dontEnums.length,
          isFunction = function isFunction(value) {
              return _toString(value) === '[object Function]';
          },
          isArguments = function isArguments(value) {
              var str = _toString(value);
              var isArgs = str === '[object Arguments]';
              if (!isArgs) {
                  isArgs = !Array.isArray(str)
                      && value !== null
                      && typeof value === 'object'
                      && typeof value.length === 'number'
                      && value.length >= 0
                      && isFunction(value.callee);
              }
              return isArgs;
          };
  
      Object.keys = function keys(object) {
          var isFn = isFunction(object),
              isArgs = isArguments(object),
              isObject = object !== null && typeof object === 'object',
              isString = isObject && _toString(object) === '[object String]';
  
          if (!isObject && !isFn && !isArgs) {
              throw new TypeError("Object.keys called on a non-object");
          }
  
          var keys = [];
          var skipProto = hasProtoEnumBug && isFn;
          if (isString || isArgs) {
              for (var i = 0; i < object.length; ++i) {
                  keys.push(String(i));
              }
          } else {
              for (var name in object) {
                  if (!(skipProto && name === 'prototype') && owns(object, name)) {
                      keys.push(String(name));
                  }
              }
          }
  
          if (hasDontEnumBug) {
              var ctor = object.constructor,
                  skipConstructor = ctor && ctor.prototype === object;
              for (var i = 0; i < dontEnumsLength; i++) {
                  var dontEnum = dontEnums[i];
                  if (!(skipConstructor && dontEnum === 'constructor') && owns(object, dontEnum)) {
                      keys.push(dontEnum);
                  }
              }
          }
          return keys;
      };
  
  }
  
  //
  // Date
  // ====
  //
  
  // ES5 15.9.5.43
  // http://es5.github.com/#x15.9.5.43
  // This function returns a String value represent the instance in time
  // represented by this Date object. The format of the String is the Date Time
  // string format defined in 15.9.1.15. All fields are present in the String.
  // The time zone is always UTC, denoted by the suffix Z. If the time value of
  // this object is not a finite Number a RangeError exception is thrown.
  var negativeDate = -62198755200000,
      negativeYearString = "-000001";
  if (
      !Date.prototype.toISOString ||
      (new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1)
  ) {
      Date.prototype.toISOString = function toISOString() {
          var result, length, value, year, month;
          if (!isFinite(this)) {
              throw new RangeError("Date.prototype.toISOString called on non-finite value.");
          }
  
          year = this.getUTCFullYear();
  
          month = this.getUTCMonth();
          // see https://github.com/es-shims/es5-shim/issues/111
          year += Math.floor(month / 12);
          month = (month % 12 + 12) % 12;
  
          // the date time string format is specified in 15.9.1.15.
          result = [month + 1, this.getUTCDate(),
              this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
          year = (
              (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
              ("00000" + Math.abs(year))
              .slice(0 <= year && year <= 9999 ? -4 : -6)
          );
  
          length = result.length;
          while (length--) {
              value = result[length];
              // pad months, days, hours, minutes, and seconds to have two
              // digits.
              if (value < 10) {
                  result[length] = "0" + value;
              }
          }
          // pad milliseconds to have three digits.
          return (
              year + "-" + result.slice(0, 2).join("-") +
              "T" + result.slice(2).join(":") + "." +
              ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
          );
      };
  }
  
  
  // ES5 15.9.5.44
  // http://es5.github.com/#x15.9.5.44
  // This function provides a String representation of a Date object for use by
  // JSON.stringify (15.12.3).
  var dateToJSONIsSupported = false;
  try {
      dateToJSONIsSupported = (
          Date.prototype.toJSON &&
          new Date(NaN).toJSON() === null &&
          new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
          Date.prototype.toJSON.call({ // generic
              toISOString: function () {
                  return true;
              }
          })
      );
  } catch (e) {
  }
  if (!dateToJSONIsSupported) {
      Date.prototype.toJSON = function toJSON(key) {
          // When the toJSON method is called with argument key, the following
          // steps are taken:
  
          // 1.  Let O be the result of calling ToObject, giving it the this
          // value as its argument.
          // 2. Let tv be toPrimitive(O, hint Number).
          var o = Object(this),
              tv = toPrimitive(o),
              toISO;
          // 3. If tv is a Number and is not finite, return null.
          if (typeof tv === "number" && !isFinite(tv)) {
              return null;
          }
          // 4. Let toISO be the result of calling the [[Get]] internal method of
          // O with argument "toISOString".
          toISO = o.toISOString;
          // 5. If IsCallable(toISO) is false, throw a TypeError exception.
          if (typeof toISO != "function") {
              throw new TypeError("toISOString property is not callable");
          }
          // 6. Return the result of calling the [[Call]] internal method of
          //  toISO with O as the this value and an empty argument list.
          return toISO.call(o);
  
          // NOTE 1 The argument is ignored.
  
          // NOTE 2 The toJSON function is intentionally generic; it does not
          // require that its this value be a Date object. Therefore, it can be
          // transferred to other kinds of objects for use as a method. However,
          // it does require that any such object have a toISOString method. An
          // object is free to use the argument key to filter its
          // stringification.
      };
  }
  
  // ES5 15.9.4.2
  // http://es5.github.com/#x15.9.4.2
  // based on work shared by Daniel Friesen (dantman)
  // http://gist.github.com/303249
  if (!Date.parse || isNaN(Date.parse("2000-01-01T00:00:00.000Z"))) {
      // XXX global assignment won't work in embeddings that use
      // an alternate object for the context.
      Date = (function(NativeDate) {
  
          // Date.length === 7
          function Date(Y, M, D, h, m, s, ms) {
              var length = arguments.length;
              if (this instanceof NativeDate) {
                  var date = length == 1 && String(Y) === Y ? // isString(Y)
                      // We explicitly pass it through parse:
                      new NativeDate(Date.parse(Y)) :
                      // We have to manually make calls depending on argument
                      // length here
                      length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
                      length >= 6 ? new NativeDate(Y, M, D, h, m, s) :
                      length >= 5 ? new NativeDate(Y, M, D, h, m) :
                      length >= 4 ? new NativeDate(Y, M, D, h) :
                      length >= 3 ? new NativeDate(Y, M, D) :
                      length >= 2 ? new NativeDate(Y, M) :
                      length >= 1 ? new NativeDate(Y) :
                                    new NativeDate();
                  // Prevent mixups with unfixed Date object
                  date.constructor = Date;
                  return date;
              }
              return NativeDate.apply(this, arguments);
          };
  
          // 15.9.1.15 Date Time String Format.
          var isoDateExpression = new RegExp("^" +
              "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
                                        // 6-digit extended year
              "(?:-(\\d{2})" + // optional month capture
              "(?:-(\\d{2})" + // optional day capture
              "(?:" + // capture hours:minutes:seconds.milliseconds
                  "T(\\d{2})" + // hours capture
                  ":(\\d{2})" + // minutes capture
                  "(?:" + // optional :seconds.milliseconds
                      ":(\\d{2})" + // seconds capture
                      "(?:(\\.\\d{1,}))?" + // milliseconds capture
                  ")?" +
              "(" + // capture UTC offset component
                  "Z|" + // UTC capture
                  "(?:" + // offset specifier +/-hours:minutes
                      "([-+])" + // sign capture
                      "(\\d{2})" + // hours offset capture
                      ":(\\d{2})" + // minutes offset capture
                  ")" +
              ")?)?)?)?" +
          "$");
  
          var months = [
              0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
          ];
  
          function dayFromMonth(year, month) {
              var t = month > 1 ? 1 : 0;
              return (
                  months[month] +
                  Math.floor((year - 1969 + t) / 4) -
                  Math.floor((year - 1901 + t) / 100) +
                  Math.floor((year - 1601 + t) / 400) +
                  365 * (year - 1970)
              );
          }
  
          function toUTC(t) {
              return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t));
          }
  
          // Copy any custom methods a 3rd party library may have added
          for (var key in NativeDate) {
              Date[key] = NativeDate[key];
          }
  
          // Copy "native" methods explicitly; they may be non-enumerable
          Date.now = NativeDate.now;
          Date.UTC = NativeDate.UTC;
          Date.prototype = NativeDate.prototype;
          Date.prototype.constructor = Date;
  
          // Upgrade Date.parse to handle simplified ISO 8601 strings
          Date.parse = function parse(string) {
              var match = isoDateExpression.exec(string);
              if (match) {
                  // parse months, days, hours, minutes, seconds, and milliseconds
                  // provide default values if necessary
                  // parse the UTC offset component
                  var year = Number(match[1]),
                      month = Number(match[2] || 1) - 1,
                      day = Number(match[3] || 1) - 1,
                      hour = Number(match[4] || 0),
                      minute = Number(match[5] || 0),
                      second = Number(match[6] || 0),
                      millisecond = Math.floor(Number(match[7] || 0) * 1000),
                      // When time zone is missed, local offset should be used
                      // (ES 5.1 bug)
                      // see https://bugs.ecmascript.org/show_bug.cgi?id=112
                      isLocalTime = Boolean(match[4] && !match[8]),
                      signOffset = match[9] === "-" ? 1 : -1,
                      hourOffset = Number(match[10] || 0),
                      minuteOffset = Number(match[11] || 0),
                      result;
                  if (
                      hour < (
                          minute > 0 || second > 0 || millisecond > 0 ?
                          24 : 25
                      ) &&
                      minute < 60 && second < 60 && millisecond < 1000 &&
                      month > -1 && month < 12 && hourOffset < 24 &&
                      minuteOffset < 60 && // detect invalid offsets
                      day > -1 &&
                      day < (
                          dayFromMonth(year, month + 1) -
                          dayFromMonth(year, month)
                      )
                  ) {
                      result = (
                          (dayFromMonth(year, month) + day) * 24 +
                          hour +
                          hourOffset * signOffset
                      ) * 60;
                      result = (
                          (result + minute + minuteOffset * signOffset) * 60 +
                          second
                      ) * 1000 + millisecond;
                      if (isLocalTime) {
                          result = toUTC(result);
                      }
                      if (-8.64e15 <= result && result <= 8.64e15) {
                          return result;
                      }
                  }
                  return NaN;
              }
              return NativeDate.parse.apply(this, arguments);
          };
  
          return Date;
      })(Date);
  }
  
  // ES5 15.9.4.4
  // http://es5.github.com/#x15.9.4.4
  if (!Date.now) {
      Date.now = function now() {
          return new Date().getTime();
      };
  }
  
  
  //
  // Number
  // ======
  //
  
  // ES5.1 15.7.4.5
  // http://es5.github.com/#x15.7.4.5
  if (!Number.prototype.toFixed || (0.00008).toFixed(3) !== '0.000' || (0.9).toFixed(0) === '0' || (1.255).toFixed(2) !== '1.25' || (1000000000000000128).toFixed(0) !== "1000000000000000128") {
      // Hide these variables and functions
      (function () {
          var base, size, data, i;
  
          base = 1e7;
          size = 6;
          data = [0, 0, 0, 0, 0, 0];
  
          function multiply(n, c) {
              var i = -1;
              while (++i < size) {
                  c += n * data[i];
                  data[i] = c % base;
                  c = Math.floor(c / base);
              }
          }
  
          function divide(n) {
              var i = size, c = 0;
              while (--i >= 0) {
                  c += data[i];
                  data[i] = Math.floor(c / n);
                  c = (c % n) * base;
              }
          }
  
          function toString() {
              var i = size;
              var s = '';
              while (--i >= 0) {
                  if (s !== '' || i === 0 || data[i] !== 0) {
                      var t = String(data[i]);
                      if (s === '') {
                          s = t;
                      } else {
                          s += '0000000'.slice(0, 7 - t.length) + t;
                      }
                  }
              }
              return s;
          }
  
          function pow(x, n, acc) {
              return (n === 0 ? acc : (n % 2 === 1 ? pow(x, n - 1, acc * x) : pow(x * x, n / 2, acc)));
          }
  
          function log(x) {
              var n = 0;
              while (x >= 4096) {
                  n += 12;
                  x /= 4096;
              }
              while (x >= 2) {
                  n += 1;
                  x /= 2;
              }
              return n;
          }
  
          Number.prototype.toFixed = function (fractionDigits) {
              var f, x, s, m, e, z, j, k;
  
              // Test for NaN and round fractionDigits down
              f = Number(fractionDigits);
              f = f !== f ? 0 : Math.floor(f);
  
              if (f < 0 || f > 20) {
                  throw new RangeError("Number.toFixed called with invalid number of decimals");
              }
  
              x = Number(this);
  
              // Test for NaN
              if (x !== x) {
                  return "NaN";
              }
  
              // If it is too big or small, return the string value of the number
              if (x <= -1e21 || x >= 1e21) {
                  return String(x);
              }
  
              s = "";
  
              if (x < 0) {
                  s = "-";
                  x = -x;
              }
  
              m = "0";
  
              if (x > 1e-21) {
                  // 1e-21 < x < 1e21
                  // -70 < log2(x) < 70
                  e = log(x * pow(2, 69, 1)) - 69;
                  z = (e < 0 ? x * pow(2, -e, 1) : x / pow(2, e, 1));
                  z *= 0x10000000000000; // Math.pow(2, 52);
                  e = 52 - e;
  
                  // -18 < e < 122
                  // x = z / 2 ^ e
                  if (e > 0) {
                      multiply(0, z);
                      j = f;
  
                      while (j >= 7) {
                          multiply(1e7, 0);
                          j -= 7;
                      }
  
                      multiply(pow(10, j, 1), 0);
                      j = e - 1;
  
                      while (j >= 23) {
                          divide(1 << 23);
                          j -= 23;
                      }
  
                      divide(1 << j);
                      multiply(1, 1);
                      divide(2);
                      m = toString();
                  } else {
                      multiply(0, z);
                      multiply(1 << (-e), 0);
                      m = toString() + '0.00000000000000000000'.slice(2, 2 + f);
                  }
              }
  
              if (f > 0) {
                  k = m.length;
  
                  if (k <= f) {
                      m = s + '0.0000000000000000000'.slice(0, f - k + 2) + m;
                  } else {
                      m = s + m.slice(0, k - f) + '.' + m.slice(k - f);
                  }
              } else {
                  m = s + m;
              }
  
              return m;
          }
      }());
  }
  
  
  //
  // String
  // ======
  //
  
  
  // ES5 15.5.4.14
  // http://es5.github.com/#x15.5.4.14
  
  // [bugfix, IE lt 9, firefox 4, Konqueror, Opera, obscure browsers]
  // Many browsers do not split properly with regular expressions or they
  // do not perform the split correctly under obscure conditions.
  // See http://blog.stevenlevithan.com/archives/cross-browser-split
  // I've tested in many browsers and this seems to cover the deviant ones:
  //    'ab'.split(/(?:ab)*/) should be ["", ""], not [""]
  //    '.'.split(/(.?)(.?)/) should be ["", ".", "", ""], not ["", ""]
  //    'tesst'.split(/(s)*/) should be ["t", undefined, "e", "s", "t"], not
  //       [undefined, "t", undefined, "e", ...]
  //    ''.split(/.?/) should be [], not [""]
  //    '.'.split(/()()/) should be ["."], not ["", "", "."]
  
  var string_split = String.prototype.split;
  if (
      'ab'.split(/(?:ab)*/).length !== 2 ||
      '.'.split(/(.?)(.?)/).length !== 4 ||
      'tesst'.split(/(s)*/)[1] === "t" ||
      ''.split(/.?/).length ||
      '.'.split(/()()/).length > 1
  ) {
      (function () {
          var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group
  
          String.prototype.split = function (separator, limit) {
              var string = this;
              if (separator === void 0 && limit === 0)
                  return [];
  
              // If `separator` is not a regex, use native split
              if (Object.prototype.toString.call(separator) !== "[object RegExp]") {
                  return string_split.apply(this, arguments);
              }
  
              var output = [],
                  flags = (separator.ignoreCase ? "i" : "") +
                          (separator.multiline  ? "m" : "") +
                          (separator.extended   ? "x" : "") + // Proposed for ES6
                          (separator.sticky     ? "y" : ""), // Firefox 3+
                  lastLastIndex = 0,
                  // Make `global` and avoid `lastIndex` issues by working with a copy
                  separator = new RegExp(separator.source, flags + "g"),
                  separator2, match, lastIndex, lastLength;
              string += ""; // Type-convert
              if (!compliantExecNpcg) {
                  // Doesn't need flags gy, but they don't hurt
                  separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
              }
              /* Values for `limit`, per the spec:
               * If undefined: 4294967295 // Math.pow(2, 32) - 1
               * If 0, Infinity, or NaN: 0
               * If positive number: limit = Math.floor(limit); if (limit > 4294967295) limit -= 4294967296;
               * If negative number: 4294967296 - Math.floor(Math.abs(limit))
               * If other: Type-convert, then use the above rules
               */
              limit = limit === void 0 ?
                  -1 >>> 0 : // Math.pow(2, 32) - 1
                  limit >>> 0; // ToUint32(limit)
              while (match = separator.exec(string)) {
                  // `separator.lastIndex` is not reliable cross-browser
                  lastIndex = match.index + match[0].length;
                  if (lastIndex > lastLastIndex) {
                      output.push(string.slice(lastLastIndex, match.index));
                      // Fix browsers whose `exec` methods don't consistently return `undefined` for
                      // nonparticipating capturing groups
                      if (!compliantExecNpcg && match.length > 1) {
                          match[0].replace(separator2, function () {
                              for (var i = 1; i < arguments.length - 2; i++) {
                                  if (arguments[i] === void 0) {
                                      match[i] = void 0;
                                  }
                              }
                          });
                      }
                      if (match.length > 1 && match.index < string.length) {
                          Array.prototype.push.apply(output, match.slice(1));
                      }
                      lastLength = match[0].length;
                      lastLastIndex = lastIndex;
                      if (output.length >= limit) {
                          break;
                      }
                  }
                  if (separator.lastIndex === match.index) {
                      separator.lastIndex++; // Avoid an infinite loop
                  }
              }
              if (lastLastIndex === string.length) {
                  if (lastLength || !separator.test("")) {
                      output.push("");
                  }
              } else {
                  output.push(string.slice(lastLastIndex));
              }
              return output.length > limit ? output.slice(0, limit) : output;
          };
      }());
  
  // [bugfix, chrome]
  // If separator is undefined, then the result array contains just one String,
  // which is the this value (converted to a String). If limit is not undefined,
  // then the output array is truncated so that it contains no more than limit
  // elements.
  // "0".split(undefined, 0) -> []
  } else if ("0".split(void 0, 0).length) {
      String.prototype.split = function(separator, limit) {
          if (separator === void 0 && limit === 0) return [];
          return string_split.apply(this, arguments);
      }
  }
  
  
  // ECMA-262, 3rd B.2.3
  // Note an ECMAScript standart, although ECMAScript 3rd Edition has a
  // non-normative section suggesting uniform semantics and it should be
  // normalized across all browsers
  // [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
  if ("".substr && "0b".substr(-1) !== "b") {
      var string_substr = String.prototype.substr;
      /**
       *  Get the substring of a string
       *  @param  {integer}  start   where to start the substring
       *  @param  {integer}  length  how many characters to return
       *  @return {string}
       */
      String.prototype.substr = function(start, length) {
          return string_substr.call(
              this,
              start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
              length
          );
      }
  }
  
  // ES5 15.5.4.20
  // whitespace from: http://es5.github.io/#x15.5.4.20
  var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
      "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
      "\u2029\uFEFF";
  if (!String.prototype.trim || ws.trim()) {
      // http://blog.stevenlevithan.com/archives/faster-trim-javascript
      // http://perfectionkills.com/whitespace-deviations/
      ws = "[" + ws + "]";
      var trimBeginRegexp = new RegExp("^" + ws + ws + "*"),
          trimEndRegexp = new RegExp(ws + ws + "*$");
      String.prototype.trim = function trim() {
          if (this === void 0 || this === null) {
              throw new TypeError("can't convert "+this+" to object");
          }
          return String(this)
              .replace(trimBeginRegexp, "")
              .replace(trimEndRegexp, "");
      };
  }
  
  // ES-5 15.1.2.2
  if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
      parseInt = (function (origParseInt) {
          var hexRegex = /^0[xX]/;
          return function parseIntES5(str, radix) {
              str = String(str).trim();
              if (!+radix) {
                  radix = hexRegex.test(str) ? 16 : 10;
              }
              return origParseInt(str, radix);
          };
      }(parseInt));
  }
  
  //
  // Util
  // ======
  //
  
  // ES5 9.4
  // http://es5.github.com/#x9.4
  // http://jsperf.com/to-integer
  
  function toInteger(n) {
      n = +n;
      if (n !== n) { // isNaN
          n = 0;
      } else if (n !== 0 && n !== (1/0) && n !== -(1/0)) {
          n = (n > 0 || -1) * Math.floor(Math.abs(n));
      }
      return n;
  }
  
  function isPrimitive(input) {
      var type = typeof input;
      return (
          input === null ||
          type === "undefined" ||
          type === "boolean" ||
          type === "number" ||
          type === "string"
      );
  }
  
  function toPrimitive(input) {
      var val, valueOf, toString;
      if (isPrimitive(input)) {
          return input;
      }
      valueOf = input.valueOf;
      if (typeof valueOf === "function") {
          val = valueOf.call(input);
          if (isPrimitive(val)) {
              return val;
          }
      }
      toString = input.toString;
      if (typeof toString === "function") {
          val = toString.call(input);
          if (isPrimitive(val)) {
              return val;
          }
      }
      throw new TypeError();
  }
  
  // ES5 9.9
  // http://es5.github.com/#x9.9
  var toObject = function (o) {
      if (o == null) { // this matches both null and undefined
          throw new TypeError("can't convert "+o+" to object");
      }
      return Object(o);
  };
  
  }));
  // yepnope.js
  // Version - 1.5.4pre
  //
  // by
  // Alex Sexton - @SlexAxton - AlexSexton[at]gmail.com
  // Ralph Holzmann - @ralphholzmann - ralphholzmann[at]gmail.com
  //
  // http://yepnopejs.com/
  // https://github.com/SlexAxton/yepnope.js/
  //
  // Tri-license - WTFPL | MIT | BSD
  //
  // Please minify before use.
  // Also available as Modernizr.load via the Modernizr Project
  //
  ( function ( window, doc, undef ) {
  
  var docElement            = doc.documentElement,
      sTimeout              = window.setTimeout,
      firstScript           = doc.getElementsByTagName( "script" )[ 0 ],
      toString              = {}.toString,
      execStack             = [],
      started               = 0,
      noop                  = function () {},
      // Before you get mad about browser sniffs, please read:
      // https://github.com/Modernizr/Modernizr/wiki/Undetectables
      // If you have a better solution, we are actively looking to solve the problem
      isGecko               = ( "MozAppearance" in docElement.style ),
      isGeckoLTE18          = isGecko && !! doc.createRange().compareNode,
      insBeforeObj          = isGeckoLTE18 ? docElement : firstScript.parentNode,
      // Thanks to @jdalton for showing us this opera detection (by way of @kangax) (and probably @miketaylr too, or whatever...)
      isOpera               = window.opera && toString.call( window.opera ) == "[object Opera]",
      isIE                  = !! doc.attachEvent && !isOpera,
      strJsElem             = isGecko ? "object" : isIE  ? "script" : "img",
      strCssElem            = isIE ? "script" : strJsElem,
      isArray               = Array.isArray || function ( obj ) {
        return toString.call( obj ) == "[object Array]";
      },
      isObject              = function ( obj ) {
        return Object(obj) === obj;
      },
      isString              = function ( s ) {
        return typeof s == "string";
      },
      isFunction            = function ( fn ) {
        return toString.call( fn ) == "[object Function]";
      },
      readFirstScript       = function() {
          if (!firstScript || !firstScript.parentNode) {
              firstScript = doc.getElementsByTagName( "script" )[ 0 ];
          }
      },
      globalFilters         = [],
      scriptCache           = {},
      prefixes              = {
        // key value pair timeout options
        timeout : function( resourceObj, prefix_parts ) {
          if ( prefix_parts.length ) {
            resourceObj['timeout'] = prefix_parts[ 0 ];
          }
          return resourceObj;
        }
      },
      handler,
      yepnope;
  
    /* Loader helper functions */
    function isFileReady ( readyState ) {
      // Check to see if any of the ways a file can be ready are available as properties on the file's element
      return ( ! readyState || readyState == "loaded" || readyState == "complete" || readyState == "uninitialized" );
    }
  
  
    // Takes a preloaded js obj (changes in different browsers) and injects it into the head
    // in the appropriate order
    function injectJs ( src, cb, attrs, timeout, /* internal use */ err, internal ) {
  	  
      var script = doc.createElement( "script" ),
          done, i;
  
      timeout = timeout || yepnope['errorTimeout'];
  
      script.src = src;
  
      // Add our extra attributes to the script element
      for ( i in attrs ) {
          script.setAttribute( i, attrs[ i ] );
      }
  
      cb = internal ? executeStack : ( cb || noop );
  
      // Bind to load events
      script.onreadystatechange = script.onload = function () {
  
        if ( ! done && isFileReady( script.readyState ) ) {
  
          // Set done to prevent this function from being called twice.
          done = 1;
          cb();
  
          // Handle memory leak in IE
          script.onload = script.onreadystatechange = null;
        }
      };
  
      // 404 Fallback
      sTimeout(function () {
        if ( ! done ) {
          done = 1;
          // Might as well pass in an error-state if we fire the 404 fallback
          cb(1);
        }
      }, timeout );
  
      // Inject script into to document
      // or immediately callback if we know there
      // was previously a timeout error
      readFirstScript();
      err ? script.onload() : firstScript.parentNode.insertBefore( script, firstScript );
    }
  
    // Takes a preloaded css obj (changes in different browsers) and injects it into the head
    function injectCss ( href, cb, attrs, timeout, /* Internal use */ err, internal ) {
  
      // Create stylesheet link
      var link = doc.createElement( "link" ),
          done, i;
  
      timeout = timeout || yepnope['errorTimeout'];
  
      cb = internal ? executeStack : ( cb || noop );
  
      // Add attributes
      link.href = href;
      link.rel  = "stylesheet";
      link.type = "text/css";
  
      // Add our extra attributes to the link element
      for ( i in attrs ) {
        link.setAttribute( i, attrs[ i ] );
      }
  
      if ( ! err ) {
        readFirstScript();
        firstScript.parentNode.insertBefore( link, firstScript );
        sTimeout(cb, 0);
      }
    }
  
    function executeStack ( ) {
      // shift an element off of the stack
      var i   = execStack.shift();
      started = 1;
  
      // if a is truthy and the first item in the stack has an src
      if ( i ) {
        // if it's a script, inject it into the head with no type attribute
        if ( i['t'] ) {
          // Inject after a timeout so FF has time to be a jerk about it and
          // not double load (ignore the cache)
          sTimeout( function () {
            (i['t'] == "c" ?  yepnope['injectCss'] : yepnope['injectJs'])( i['s'], 0, i['a'], i['x'], i['e'], 1 );
          }, 0 );
        }
        // Otherwise, just call the function and potentially run the stack
        else {
          i();
          executeStack();
        }
      }
      else {
        // just reset out of recursive mode
        started = 0;
      }
    }
  
    function preloadFile ( elem, url, type, splicePoint, dontExec, attrObj, timeout ) {
  
      timeout = timeout || yepnope['errorTimeout'];
  
      // Create appropriate element for browser and type
      var preloadElem = doc.createElement( elem ),
          done        = 0,
          firstFlag   = 0,
          stackObject = {
            "t": type,     // type
            "s": url,      // src
          //r: 0,        // ready
            "e": dontExec,// set to true if we don't want to reinject
            "a": attrObj,
            "x": timeout
          };
  
      // The first time (common-case)
      if ( scriptCache[ url ] === 1 ) {
        firstFlag = 1;
        scriptCache[ url ] = [];
      }
  
      function onload ( first ) {
        // If the script/css file is loaded
        if ( ! done && isFileReady( preloadElem.readyState ) ) {
  
          // Set done to prevent this function from being called twice.
          stackObject['r'] = done = 1;
  
          ! started && executeStack();
  
          if ( first ) {
            if ( elem != "img" ) {
              sTimeout(function(){ insBeforeObj.removeChild( preloadElem ) }, 50);
            }
  
            for ( var i in scriptCache[ url ] ) {
              if ( scriptCache[ url ].hasOwnProperty( i ) ) {
                scriptCache[ url ][ i ].onload();
              }
            }
            
            // Handle memory leak in IE
             preloadElem.onload = preloadElem.onreadystatechange = null;
          }
        }
      }
  
  
      // Setting url to data for objects or src for img/scripts
      if ( elem == "object" ) {
        preloadElem.data = url;
  	  
        // Setting the type attribute to stop Firefox complaining about the mimetype when running locally.
        // The type doesn't matter as long as it's real, thus text/css instead of text/javascript.
        preloadElem.setAttribute("type", "text/css");
      } else {
        preloadElem.src = url;
  
        // Setting bogus script type to allow the script to be cached
        preloadElem.type = elem;
      }
  
      // Don't let it show up visually
      preloadElem.width = preloadElem.height = "0";
  
      // Attach handlers for all browsers
      preloadElem.onerror = preloadElem.onload = preloadElem.onreadystatechange = function(){
        onload.call(this, firstFlag);
      };
      // inject the element into the stack depending on if it's
      // in the middle of other scripts or not
      execStack.splice( splicePoint, 0, stackObject );
  
      // The only place these can't go is in the <head> element, since objects won't load in there
      // so we have two options - insert before the head element (which is hard to assume) - or
      // insertBefore technically takes null/undefined as a second param and it will insert the element into
      // the parent last. We try the head, and it automatically falls back to undefined.
      if ( elem != "img" ) {
        // If it's the first time, or we've already loaded it all the way through
        if ( firstFlag || scriptCache[ url ] === 2 ) {
          readFirstScript();
          insBeforeObj.insertBefore( preloadElem, isGeckoLTE18 ? null : firstScript );
  
          // If something fails, and onerror doesn't fire,
          // continue after a timeout.
          sTimeout( onload, timeout );
        }
        else {
          // instead of injecting, just hold on to it
          scriptCache[ url ].push( preloadElem );
        }
      }
    }
  
    function load ( resource, type, dontExec, attrObj, timeout ) {
      // If this method gets hit multiple times, we should flag
      // that the execution of other threads should halt.
      started = 0;
  
      // We'll do 'j' for js and 'c' for css, yay for unreadable minification tactics
      type = type || "j";
      if ( isString( resource ) ) {
        // if the resource passed in here is a string, preload the file
        preloadFile( type == "c" ? strCssElem : strJsElem, resource, type, this['i']++, dontExec, attrObj, timeout );
      } else {
        // Otherwise it's a callback function and we can splice it into the stack to run
        execStack.splice( this['i']++, 0, resource );
        execStack.length == 1 && executeStack();
      }
  
      // OMG is this jQueries? For chaining...
      return this;
    }
  
    // return the yepnope object with a fresh loader attached
    function getYepnope () {
      var y = yepnope;
      y['loader'] = {
        "load": load,
        "i" : 0
      };
      return y;
    }
  
    /* End loader helper functions */
    // Yepnope Function
    yepnope = function ( needs ) {
  
      var i,
          need,
          // start the chain as a plain instance
          chain = this['yepnope']['loader'];
  
      function satisfyPrefixes ( url ) {
        // split all prefixes out
        var parts   = url.split( "!" ),
        gLen    = globalFilters.length,
        origUrl = parts.pop(),
        pLen    = parts.length,
        res     = {
          "url"      : origUrl,
          // keep this one static for callback variable consistency
          "origUrl"  : origUrl,
          "prefixes" : parts
        },
        mFunc,
        j,
        prefix_parts;
  
        // loop through prefixes
        // if there are none, this automatically gets skipped
        for ( j = 0; j < pLen; j++ ) {
          prefix_parts = parts[ j ].split( '=' );
          mFunc = prefixes[ prefix_parts.shift() ];
          if ( mFunc ) {
            res = mFunc( res, prefix_parts );
          }
        }
  
        // Go through our global filters
        for ( j = 0; j < gLen; j++ ) {
          res = globalFilters[ j ]( res );
        }
  
        // return the final url
        return res;
      }
  
       function getExtension ( url ) {
        //The extension is always the last characters before the ? and after a period.
        //The previous method was not accounting for the possibility of a period in the query string.
        var b = url.split('?')[0];
        return b.substr(b.lastIndexOf('.')+1);
      }
  
      function loadScriptOrStyle ( input, callback, chain, index, testResult ) {
        // run through our set of prefixes
        var resource     = satisfyPrefixes( input ),
            autoCallback = resource['autoCallback'],
            extension    = getExtension( resource['url'] );
  
        // if no object is returned or the url is empty/0 just exit the load
        if ( resource['bypass'] ) {
          return;
        }
  
        // Determine callback, if any
        if ( callback ) {
          callback = isFunction( callback ) ?
            callback :
            callback[ input ] ||
            callback[ index ] ||
            callback[ ( input.split( "/" ).pop().split( "?" )[ 0 ] ) ];
        }
  
        // if someone is overriding all normal functionality
        if ( resource['instead'] ) {
          return resource['instead']( input, callback, chain, index, testResult );
        }
        else {
          // Handle if we've already had this url and it's completed loaded already
          if ( scriptCache[ resource['url'] ] && resource['reexecute'] !== true) {
            // don't let this execute again
            resource['noexec'] = true;
          }
          else {
            scriptCache[ resource['url'] ] = 1;
          }
  
          // Throw this into the queue
          chain.load( resource['url'], ( ( resource['forceCSS'] || ( ! resource['forceJS'] && "css" == getExtension( resource['url'] ) ) ) ) ? "c" : undef, resource['noexec'], resource['attrs'], resource['timeout'] );
  
          // If we have a callback, we'll start the chain over
          if ( isFunction( callback ) || isFunction( autoCallback ) ) {
            // Call getJS with our current stack of things
            chain['load']( function () {
              // Hijack yepnope and restart index counter
              getYepnope();
              // Call our callbacks with this set of data
              callback && callback( resource['origUrl'], testResult, index );
              autoCallback && autoCallback( resource['origUrl'], testResult, index );
  
              // Override this to just a boolean positive
              scriptCache[ resource['url'] ] = 2;
            } );
          }
        }
      }
  
      function loadFromTestObject ( testObject, chain ) {
          var testResult = !! testObject['test'],
              group      = testResult ? testObject['yep'] : testObject['nope'],
              always     = testObject['load'] || testObject['both'],
              callback   = testObject['callback'] || noop,
              cbRef      = callback,
              complete   = testObject['complete'] || noop,
              needGroupSize,
              callbackKey;
              
          // Reusable function for dealing with the different input types
          // NOTE:: relies on closures to keep 'chain' up to date, a bit confusing, but
          // much smaller than the functional equivalent in this case.
          function handleGroup ( needGroup, moreToCome ) {
            if ( ! needGroup ) {
              // Call the complete callback when there's nothing to load.
              ! moreToCome && complete();
            }
            // If it's a string
            else if ( isString( needGroup ) ) {
              // if it's a string, it's the last
              if ( !moreToCome ) {
                // Add in the complete callback to go at the end
                callback = function () {
                  var args = [].slice.call( arguments );
                  cbRef.apply( this, args );
                  complete();
                };
              }
              // Just load the script of style
              loadScriptOrStyle( needGroup, callback, chain, 0, testResult );
            }
            // See if we have an object. Doesn't matter if it's an array or a key/val hash
            // Note:: order cannot be guaranteed on an key value object with multiple elements
            // since the for-in does not preserve order. Arrays _should_ go in order though.
            else if ( isObject( needGroup ) ) {
              // I hate this, but idk another way for objects.
              needGroupSize = (function(){
                var count = 0, i
                for (i in needGroup ) {
                  if ( needGroup.hasOwnProperty( i ) ) {
                    count++;
                  }
                }
                return count;
              })();
  
              for ( callbackKey in needGroup ) {
                // Safari 2 does not have hasOwnProperty, but not worth the bytes for a shim
                // patch if needed. Kangax has a nice shim for it. Or just remove the check
                // and promise not to extend the object prototype.
                if ( needGroup.hasOwnProperty( callbackKey ) ) {
                  // Find the last added resource, and append to it's callback.
                  if ( ! moreToCome && ! ( --needGroupSize ) ) {
                    // If this is an object full of callbacks
                    if ( ! isFunction( callback ) ) {
                      // Add in the complete callback to go at the end
                      callback[ callbackKey ] = (function( innerCb ) {
                        return function () {
                          var args = [].slice.call( arguments );
                          innerCb && innerCb.apply( this, args );
                          complete();
                        };
                      })( cbRef[ callbackKey ] );
                    }
                    // If this is just a single callback
                    else {
                      callback = function () {
                        var args = [].slice.call( arguments );
                        cbRef.apply( this, args );
                        complete();
                      };
                    }
                  }
                  loadScriptOrStyle( needGroup[ callbackKey ], callback, chain, callbackKey, testResult );
                }
              }
            }
          }
  
          // figure out what this group should do
          handleGroup( group, !!always );
  
          // Run our loader on the load/both group too
          // the always stuff always loads second.
          always && handleGroup( always );
      }
  
      // Someone just decides to load a single script or css file as a string
      if ( isString( needs ) ) {
        loadScriptOrStyle( needs, 0, chain, 0 );
      }
      // Normal case is likely an array of different types of loading options
      else if ( isArray( needs ) ) {
        // go through the list of needs
        for( i = 0; i < needs.length; i++ ) {
          need = needs[ i ];
  
          // if it's a string, just load it
          if ( isString( need ) ) {
            loadScriptOrStyle( need, 0, chain, 0 );
          }
          // if it's an array, call our function recursively
          else if ( isArray( need ) ) {
            yepnope( need );
          }
          // if it's an object, use our modernizr logic to win
          else if ( isObject( need ) ) {
            loadFromTestObject( need, chain );
          }
        }
      }
      // Allow a single object to be passed in
      else if ( isObject( needs ) ) {
        loadFromTestObject( needs, chain );
      }
    };
  
    // This publicly exposed function is for allowing
    // you to add functionality based on prefixes on the
    // string files you add. 'css!' is a builtin prefix
    //
    // The arguments are the prefix (not including the !) as a string
    // and
    // A callback function. This function is passed a resource object
    // that can be manipulated and then returned. (like middleware. har.)
    //
    // Examples of this can be seen in the officially supported ie prefix
    yepnope['addPrefix'] = function ( prefix, callback ) {
      prefixes[ prefix ] = callback;
    };
  
    // A filter is a global function that every resource
    // object that passes through yepnope will see. You can
    // of course conditionally choose to modify the resource objects
    // or just pass them along. The filter function takes the resource
    // object and is expected to return one.
    //
    // The best example of a filter is the 'autoprotocol' officially
    // supported filter
    yepnope['addFilter'] = function ( filter ) {
      globalFilters.push( filter );
    };
  
    // Default error timeout to 10sec - modify to alter
    yepnope['errorTimeout'] = 1e4;
  
    // Webreflection readystate hack
    // safe for jQuery 1.4+ ( i.e. don't use yepnope with jQuery 1.3.2 )
    // if the readyState is null and we have a listener
    if ( doc.readyState == null && doc.addEventListener ) {
      // set the ready state to loading
      doc.readyState = "loading";
      // call the listener
      doc.addEventListener( "DOMContentLoaded", handler = function () {
        // Remove the listener
        doc.removeEventListener( "DOMContentLoaded", handler, 0 );
        // Set it to ready
        doc.readyState = "complete";
      }, 0 );
    }
  
    // Attach loader &
    // Leak it
    window['yepnope'] = getYepnope();
  
    // Exposing executeStack to better facilitate plugins
    window['yepnope']['executeStack'] = executeStack;
    window['yepnope']['injectJs'] = injectJs;
    window['yepnope']['injectCss'] = injectCss;
  
  })( this, document );
  //     Underscore.js 1.4.3
  //     http://underscorejs.org
  //     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
  //     Underscore may be freely distributed under the MIT license.
  
  (function() {
  
    // Baseline setup
    // --------------
  
    // Establish the root object, `window` in the browser, or `global` on the server.
    var root = this;
  
    // Save the previous value of the `_` variable.
    var previousUnderscore = root._;
  
    // Establish the object that gets returned to break out of a loop iteration.
    var breaker = {};
  
    // Save bytes in the minified (but not gzipped) version:
    var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
  
    // Create quick reference variables for speed access to core prototypes.
    var push             = ArrayProto.push,
        slice            = ArrayProto.slice,
        concat           = ArrayProto.concat,
        toString         = ObjProto.toString,
        hasOwnProperty   = ObjProto.hasOwnProperty;
  
    // All **ECMAScript 5** native function implementations that we hope to use
    // are declared here.
    var
      nativeForEach      = ArrayProto.forEach,
      nativeMap          = ArrayProto.map,
      nativeReduce       = ArrayProto.reduce,
      nativeReduceRight  = ArrayProto.reduceRight,
      nativeFilter       = ArrayProto.filter,
      nativeEvery        = ArrayProto.every,
      nativeSome         = ArrayProto.some,
      nativeIndexOf      = ArrayProto.indexOf,
      nativeLastIndexOf  = ArrayProto.lastIndexOf,
      nativeIsArray      = Array.isArray,
      nativeKeys         = Object.keys,
      nativeBind         = FuncProto.bind;
  
    // Create a safe reference to the Underscore object for use below.
    var _ = function(obj) {
      if (obj instanceof _) return obj;
      if (!(this instanceof _)) return new _(obj);
      this._wrapped = obj;
    };
  
    // Export the Underscore object for **Node.js**, with
    // backwards-compatibility for the old `require()` API. If we're in
    // the browser, add `_` as a global object via a string identifier,
    // for Closure Compiler "advanced" mode.
    if (typeof exports !== 'undefined') {
      if (typeof module !== 'undefined' && module.exports) {
        exports = module.exports = _;
      }
      exports._ = _;
    } else {
      root._ = _;
    }
  
    // Current version.
    _.VERSION = '1.4.3';
  
    // Collection Functions
    // --------------------
  
    // The cornerstone, an `each` implementation, aka `forEach`.
    // Handles objects with the built-in `forEach`, arrays, and raw objects.
    // Delegates to **ECMAScript 5**'s native `forEach` if available.
    var each = _.each = _.forEach = function(obj, iterator, context) {
      if (obj == null) return;
      if (nativeForEach && obj.forEach === nativeForEach) {
        obj.forEach(iterator, context);
      } else if (obj.length === +obj.length) {
        for (var i = 0, l = obj.length; i < l; i++) {
          if (iterator.call(context, obj[i], i, obj) === breaker) return;
        }
      } else {
        for (var key in obj) {
          if (_.has(obj, key)) {
            if (iterator.call(context, obj[key], key, obj) === breaker) return;
          }
        }
      }
    };
  
    // Return the results of applying the iterator to each element.
    // Delegates to **ECMAScript 5**'s native `map` if available.
    _.map = _.collect = function(obj, iterator, context) {
      var results = [];
      if (obj == null) return results;
      if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
      each(obj, function(value, index, list) {
        results[results.length] = iterator.call(context, value, index, list);
      });
      return results;
    };
  
    var reduceError = 'Reduce of empty array with no initial value';
  
    // **Reduce** builds up a single result from a list of values, aka `inject`,
    // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
    _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
      var initial = arguments.length > 2;
      if (obj == null) obj = [];
      if (nativeReduce && obj.reduce === nativeReduce) {
        if (context) iterator = _.bind(iterator, context);
        return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
      }
      each(obj, function(value, index, list) {
        if (!initial) {
          memo = value;
          initial = true;
        } else {
          memo = iterator.call(context, memo, value, index, list);
        }
      });
      if (!initial) throw new TypeError(reduceError);
      return memo;
    };
  
    // The right-associative version of reduce, also known as `foldr`.
    // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
    _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
      var initial = arguments.length > 2;
      if (obj == null) obj = [];
      if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
        if (context) iterator = _.bind(iterator, context);
        return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
      }
      var length = obj.length;
      if (length !== +length) {
        var keys = _.keys(obj);
        length = keys.length;
      }
      each(obj, function(value, index, list) {
        index = keys ? keys[--length] : --length;
        if (!initial) {
          memo = obj[index];
          initial = true;
        } else {
          memo = iterator.call(context, memo, obj[index], index, list);
        }
      });
      if (!initial) throw new TypeError(reduceError);
      return memo;
    };
  
    // Return the first value which passes a truth test. Aliased as `detect`.
    _.find = _.detect = function(obj, iterator, context) {
      var result;
      any(obj, function(value, index, list) {
        if (iterator.call(context, value, index, list)) {
          result = value;
          return true;
        }
      });
      return result;
    };
  
    // Return all the elements that pass a truth test.
    // Delegates to **ECMAScript 5**'s native `filter` if available.
    // Aliased as `select`.
    _.filter = _.select = function(obj, iterator, context) {
      var results = [];
      if (obj == null) return results;
      if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
      each(obj, function(value, index, list) {
        if (iterator.call(context, value, index, list)) results[results.length] = value;
      });
      return results;
    };
  
    // Return all the elements for which a truth test fails.
    _.reject = function(obj, iterator, context) {
      return _.filter(obj, function(value, index, list) {
        return !iterator.call(context, value, index, list);
      }, context);
    };
  
    // Determine whether all of the elements match a truth test.
    // Delegates to **ECMAScript 5**'s native `every` if available.
    // Aliased as `all`.
    _.every = _.all = function(obj, iterator, context) {
      iterator || (iterator = _.identity);
      var result = true;
      if (obj == null) return result;
      if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
      each(obj, function(value, index, list) {
        if (!(result = result && iterator.call(context, value, index, list))) return breaker;
      });
      return !!result;
    };
  
    // Determine if at least one element in the object matches a truth test.
    // Delegates to **ECMAScript 5**'s native `some` if available.
    // Aliased as `any`.
    var any = _.some = _.any = function(obj, iterator, context) {
      iterator || (iterator = _.identity);
      var result = false;
      if (obj == null) return result;
      if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
      each(obj, function(value, index, list) {
        if (result || (result = iterator.call(context, value, index, list))) return breaker;
      });
      return !!result;
    };
  
    // Determine if the array or object contains a given value (using `===`).
    // Aliased as `include`.
    _.contains = _.include = function(obj, target) {
      if (obj == null) return false;
      if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
      return any(obj, function(value) {
        return value === target;
      });
    };
  
    // Invoke a method (with arguments) on every item in a collection.
    _.invoke = function(obj, method) {
      var args = slice.call(arguments, 2);
      return _.map(obj, function(value) {
        return (_.isFunction(method) ? method : value[method]).apply(value, args);
      });
    };
  
    // Convenience version of a common use case of `map`: fetching a property.
    _.pluck = function(obj, key) {
      return _.map(obj, function(value){ return value[key]; });
    };
  
    // Convenience version of a common use case of `filter`: selecting only objects
    // with specific `key:value` pairs.
    _.where = function(obj, attrs) {
      if (_.isEmpty(attrs)) return [];
      return _.filter(obj, function(value) {
        for (var key in attrs) {
          if (attrs[key] !== value[key]) return false;
        }
        return true;
      });
    };
  
    // Return the maximum element or (element-based computation).
    // Can't optimize arrays of integers longer than 65,535 elements.
    // See: https://bugs.webkit.org/show_bug.cgi?id=80797
    _.max = function(obj, iterator, context) {
      if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
        return Math.max.apply(Math, obj);
      }
      if (!iterator && _.isEmpty(obj)) return -Infinity;
      var result = {computed : -Infinity, value: -Infinity};
      each(obj, function(value, index, list) {
        var computed = iterator ? iterator.call(context, value, index, list) : value;
        computed >= result.computed && (result = {value : value, computed : computed});
      });
      return result.value;
    };
  
    // Return the minimum element (or element-based computation).
    _.min = function(obj, iterator, context) {
      if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
        return Math.min.apply(Math, obj);
      }
      if (!iterator && _.isEmpty(obj)) return Infinity;
      var result = {computed : Infinity, value: Infinity};
      each(obj, function(value, index, list) {
        var computed = iterator ? iterator.call(context, value, index, list) : value;
        computed < result.computed && (result = {value : value, computed : computed});
      });
      return result.value;
    };
  
    // Shuffle an array.
    _.shuffle = function(obj) {
      var rand;
      var index = 0;
      var shuffled = [];
      each(obj, function(value) {
        rand = _.random(index++);
        shuffled[index - 1] = shuffled[rand];
        shuffled[rand] = value;
      });
      return shuffled;
    };
  
    // An internal function to generate lookup iterators.
    var lookupIterator = function(value) {
      return _.isFunction(value) ? value : function(obj){ return obj[value]; };
    };
  
    // Sort the object's values by a criterion produced by an iterator.
    _.sortBy = function(obj, value, context) {
      var iterator = lookupIterator(value);
      return _.pluck(_.map(obj, function(value, index, list) {
        return {
          value : value,
          index : index,
          criteria : iterator.call(context, value, index, list)
        };
      }).sort(function(left, right) {
        var a = left.criteria;
        var b = right.criteria;
        if (a !== b) {
          if (a > b || a === void 0) return 1;
          if (a < b || b === void 0) return -1;
        }
        return left.index < right.index ? -1 : 1;
      }), 'value');
    };
  
    // An internal function used for aggregate "group by" operations.
    var group = function(obj, value, context, behavior) {
      var result = {};
      var iterator = lookupIterator(value || _.identity);
      each(obj, function(value, index) {
        var key = iterator.call(context, value, index, obj);
        behavior(result, key, value);
      });
      return result;
    };
  
    // Groups the object's values by a criterion. Pass either a string attribute
    // to group by, or a function that returns the criterion.
    _.groupBy = function(obj, value, context) {
      return group(obj, value, context, function(result, key, value) {
        (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
      });
    };
  
    // Counts instances of an object that group by a certain criterion. Pass
    // either a string attribute to count by, or a function that returns the
    // criterion.
    _.countBy = function(obj, value, context) {
      return group(obj, value, context, function(result, key) {
        if (!_.has(result, key)) result[key] = 0;
        result[key]++;
      });
    };
  
    // Use a comparator function to figure out the smallest index at which
    // an object should be inserted so as to maintain order. Uses binary search.
    _.sortedIndex = function(array, obj, iterator, context) {
      iterator = iterator == null ? _.identity : lookupIterator(iterator);
      var value = iterator.call(context, obj);
      var low = 0, high = array.length;
      while (low < high) {
        var mid = (low + high) >>> 1;
        iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
      }
      return low;
    };
  
    // Safely convert anything iterable into a real, live array.
    _.toArray = function(obj) {
      if (!obj) return [];
      if (_.isArray(obj)) return slice.call(obj);
      if (obj.length === +obj.length) return _.map(obj, _.identity);
      return _.values(obj);
    };
  
    // Return the number of elements in an object.
    _.size = function(obj) {
      if (obj == null) return 0;
      return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
    };
  
    // Array Functions
    // ---------------
  
    // Get the first element of an array. Passing **n** will return the first N
    // values in the array. Aliased as `head` and `take`. The **guard** check
    // allows it to work with `_.map`.
    _.first = _.head = _.take = function(array, n, guard) {
      if (array == null) return void 0;
      return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
    };
  
    // Returns everything but the last entry of the array. Especially useful on
    // the arguments object. Passing **n** will return all the values in
    // the array, excluding the last N. The **guard** check allows it to work with
    // `_.map`.
    _.initial = function(array, n, guard) {
      return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
    };
  
    // Get the last element of an array. Passing **n** will return the last N
    // values in the array. The **guard** check allows it to work with `_.map`.
    _.last = function(array, n, guard) {
      if (array == null) return void 0;
      if ((n != null) && !guard) {
        return slice.call(array, Math.max(array.length - n, 0));
      } else {
        return array[array.length - 1];
      }
    };
  
    // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    // Especially useful on the arguments object. Passing an **n** will return
    // the rest N values in the array. The **guard**
    // check allows it to work with `_.map`.
    _.rest = _.tail = _.drop = function(array, n, guard) {
      return slice.call(array, (n == null) || guard ? 1 : n);
    };
  
    // Trim out all falsy values from an array.
    _.compact = function(array) {
      return _.filter(array, _.identity);
    };
  
    // Internal implementation of a recursive `flatten` function.
    var flatten = function(input, shallow, output) {
      each(input, function(value) {
        if (_.isArray(value)) {
          shallow ? push.apply(output, value) : flatten(value, shallow, output);
        } else {
          output.push(value);
        }
      });
      return output;
    };
  
    // Return a completely flattened version of an array.
    _.flatten = function(array, shallow) {
      return flatten(array, shallow, []);
    };
  
    // Return a version of the array that does not contain the specified value(s).
    _.without = function(array) {
      return _.difference(array, slice.call(arguments, 1));
    };
  
    // Produce a duplicate-free version of the array. If the array has already
    // been sorted, you have the option of using a faster algorithm.
    // Aliased as `unique`.
    _.uniq = _.unique = function(array, isSorted, iterator, context) {
      if (_.isFunction(isSorted)) {
        context = iterator;
        iterator = isSorted;
        isSorted = false;
      }
      var initial = iterator ? _.map(array, iterator, context) : array;
      var results = [];
      var seen = [];
      each(initial, function(value, index) {
        if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
          seen.push(value);
          results.push(array[index]);
        }
      });
      return results;
    };
  
    // Produce an array that contains the union: each distinct element from all of
    // the passed-in arrays.
    _.union = function() {
      return _.uniq(concat.apply(ArrayProto, arguments));
    };
  
    // Produce an array that contains every item shared between all the
    // passed-in arrays.
    _.intersection = function(array) {
      var rest = slice.call(arguments, 1);
      return _.filter(_.uniq(array), function(item) {
        return _.every(rest, function(other) {
          return _.indexOf(other, item) >= 0;
        });
      });
    };
  
    // Take the difference between one array and a number of other arrays.
    // Only the elements present in just the first array will remain.
    _.difference = function(array) {
      var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
      return _.filter(array, function(value){ return !_.contains(rest, value); });
    };
  
    // Zip together multiple lists into a single array -- elements that share
    // an index go together.
    _.zip = function() {
      var args = slice.call(arguments);
      var length = _.max(_.pluck(args, 'length'));
      var results = new Array(length);
      for (var i = 0; i < length; i++) {
        results[i] = _.pluck(args, "" + i);
      }
      return results;
    };
  
    // Converts lists into objects. Pass either a single array of `[key, value]`
    // pairs, or two parallel arrays of the same length -- one of keys, and one of
    // the corresponding values.
    _.object = function(list, values) {
      if (list == null) return {};
      var result = {};
      for (var i = 0, l = list.length; i < l; i++) {
        if (values) {
          result[list[i]] = values[i];
        } else {
          result[list[i][0]] = list[i][1];
        }
      }
      return result;
    };
  
    // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
    // we need this function. Return the position of the first occurrence of an
    // item in an array, or -1 if the item is not included in the array.
    // Delegates to **ECMAScript 5**'s native `indexOf` if available.
    // If the array is large and already in sort order, pass `true`
    // for **isSorted** to use binary search.
    _.indexOf = function(array, item, isSorted) {
      if (array == null) return -1;
      var i = 0, l = array.length;
      if (isSorted) {
        if (typeof isSorted == 'number') {
          i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
        } else {
          i = _.sortedIndex(array, item);
          return array[i] === item ? i : -1;
        }
      }
      if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
      for (; i < l; i++) if (array[i] === item) return i;
      return -1;
    };
  
    // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
    _.lastIndexOf = function(array, item, from) {
      if (array == null) return -1;
      var hasIndex = from != null;
      if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
        return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
      }
      var i = (hasIndex ? from : array.length);
      while (i--) if (array[i] === item) return i;
      return -1;
    };
  
    // Generate an integer Array containing an arithmetic progression. A port of
    // the native Python `range()` function. See
    // [the Python documentation](http://docs.python.org/library/functions.html#range).
    _.range = function(start, stop, step) {
      if (arguments.length <= 1) {
        stop = start || 0;
        start = 0;
      }
      step = arguments[2] || 1;
  
      var len = Math.max(Math.ceil((stop - start) / step), 0);
      var idx = 0;
      var range = new Array(len);
  
      while(idx < len) {
        range[idx++] = start;
        start += step;
      }
  
      return range;
    };
  
    // Function (ahem) Functions
    // ------------------
  
    // Reusable constructor function for prototype setting.
    var ctor = function(){};
  
    // Create a function bound to a given object (assigning `this`, and arguments,
    // optionally). Binding with arguments is also known as `curry`.
    // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
    // We check for `func.bind` first, to fail fast when `func` is undefined.
    _.bind = function(func, context) {
      var args, bound;
      if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
      if (!_.isFunction(func)) throw new TypeError;
      args = slice.call(arguments, 2);
      return bound = function() {
        if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
        ctor.prototype = func.prototype;
        var self = new ctor;
        ctor.prototype = null;
        var result = func.apply(self, args.concat(slice.call(arguments)));
        if (Object(result) === result) return result;
        return self;
      };
    };
  
    // Bind all of an object's methods to that object. Useful for ensuring that
    // all callbacks defined on an object belong to it.
    _.bindAll = function(obj) {
      var funcs = slice.call(arguments, 1);
      if (funcs.length == 0) funcs = _.functions(obj);
      each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
      return obj;
    };
  
    // Memoize an expensive function by storing its results.
    _.memoize = function(func, hasher) {
      var memo = {};
      hasher || (hasher = _.identity);
      return function() {
        var key = hasher.apply(this, arguments);
        return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
      };
    };
  
    // Delays a function for the given number of milliseconds, and then calls
    // it with the arguments supplied.
    _.delay = function(func, wait) {
      var args = slice.call(arguments, 2);
      return setTimeout(function(){ return func.apply(null, args); }, wait);
    };
  
    // Defers a function, scheduling it to run after the current call stack has
    // cleared.
    _.defer = function(func) {
      return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
    };
  
    // Returns a function, that, when invoked, will only be triggered at most once
    // during a given window of time.
    _.throttle = function(func, wait) {
      var context, args, timeout, result;
      var previous = 0;
      var later = function() {
        previous = new Date;
        timeout = null;
        result = func.apply(context, args);
      };
      return function() {
        var now = new Date;
        var remaining = wait - (now - previous);
        context = this;
        args = arguments;
        if (remaining <= 0) {
          clearTimeout(timeout);
          timeout = null;
          previous = now;
          result = func.apply(context, args);
        } else if (!timeout) {
          timeout = setTimeout(later, remaining);
        }
        return result;
      };
    };
  
    // Returns a function, that, as long as it continues to be invoked, will not
    // be triggered. The function will be called after it stops being called for
    // N milliseconds. If `immediate` is passed, trigger the function on the
    // leading edge, instead of the trailing.
    _.debounce = function(func, wait, immediate) {
      var timeout, result;
      return function() {
        var context = this, args = arguments;
        var later = function() {
          timeout = null;
          if (!immediate) result = func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) result = func.apply(context, args);
        return result;
      };
    };
  
    // Returns a function that will be executed at most one time, no matter how
    // often you call it. Useful for lazy initialization.
    _.once = function(func) {
      var ran = false, memo;
      return function() {
        if (ran) return memo;
        ran = true;
        memo = func.apply(this, arguments);
        func = null;
        return memo;
      };
    };
  
    // Returns the first function passed as an argument to the second,
    // allowing you to adjust arguments, run code before and after, and
    // conditionally execute the original function.
    _.wrap = function(func, wrapper) {
      return function() {
        var args = [func];
        push.apply(args, arguments);
        return wrapper.apply(this, args);
      };
    };
  
    // Returns a function that is the composition of a list of functions, each
    // consuming the return value of the function that follows.
    _.compose = function() {
      var funcs = arguments;
      return function() {
        var args = arguments;
        for (var i = funcs.length - 1; i >= 0; i--) {
          args = [funcs[i].apply(this, args)];
        }
        return args[0];
      };
    };
  
    // Returns a function that will only be executed after being called N times.
    _.after = function(times, func) {
      if (times <= 0) return func();
      return function() {
        if (--times < 1) {
          return func.apply(this, arguments);
        }
      };
    };
  
    // Object Functions
    // ----------------
  
    // Retrieve the names of an object's properties.
    // Delegates to **ECMAScript 5**'s native `Object.keys`
    _.keys = nativeKeys || function(obj) {
      if (obj !== Object(obj)) throw new TypeError('Invalid object');
      var keys = [];
      for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
      return keys;
    };
  
    // Retrieve the values of an object's properties.
    _.values = function(obj) {
      var values = [];
      for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
      return values;
    };
  
    // Convert an object into a list of `[key, value]` pairs.
    _.pairs = function(obj) {
      var pairs = [];
      for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
      return pairs;
    };
  
    // Invert the keys and values of an object. The values must be serializable.
    _.invert = function(obj) {
      var result = {};
      for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
      return result;
    };
  
    // Return a sorted list of the function names available on the object.
    // Aliased as `methods`
    _.functions = _.methods = function(obj) {
      var names = [];
      for (var key in obj) {
        if (_.isFunction(obj[key])) names.push(key);
      }
      return names.sort();
    };
  
    // Extend a given object with all the properties in passed-in object(s).
    _.extend = function(obj) {
      each(slice.call(arguments, 1), function(source) {
        if (source) {
          for (var prop in source) {
            obj[prop] = source[prop];
          }
        }
      });
      return obj;
    };
  
    // Return a copy of the object only containing the whitelisted properties.
    _.pick = function(obj) {
      var copy = {};
      var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
      each(keys, function(key) {
        if (key in obj) copy[key] = obj[key];
      });
      return copy;
    };
  
     // Return a copy of the object without the blacklisted properties.
    _.omit = function(obj) {
      var copy = {};
      var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
      for (var key in obj) {
        if (!_.contains(keys, key)) copy[key] = obj[key];
      }
      return copy;
    };
  
    // Fill in a given object with default properties.
    _.defaults = function(obj) {
      each(slice.call(arguments, 1), function(source) {
        if (source) {
          for (var prop in source) {
            if (obj[prop] == null) obj[prop] = source[prop];
          }
        }
      });
      return obj;
    };
  
    // Create a (shallow-cloned) duplicate of an object.
    _.clone = function(obj) {
      if (!_.isObject(obj)) return obj;
      return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    };
  
    // Invokes interceptor with the obj, and then returns obj.
    // The primary purpose of this method is to "tap into" a method chain, in
    // order to perform operations on intermediate results within the chain.
    _.tap = function(obj, interceptor) {
      interceptor(obj);
      return obj;
    };
  
    // Internal recursive comparison function for `isEqual`.
    var eq = function(a, b, aStack, bStack) {
      // Identical objects are equal. `0 === -0`, but they aren't identical.
      // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
      if (a === b) return a !== 0 || 1 / a == 1 / b;
      // A strict comparison is necessary because `null == undefined`.
      if (a == null || b == null) return a === b;
      // Unwrap any wrapped objects.
      if (a instanceof _) a = a._wrapped;
      if (b instanceof _) b = b._wrapped;
      // Compare `[[Class]]` names.
      var className = toString.call(a);
      if (className != toString.call(b)) return false;
      switch (className) {
        // Strings, numbers, dates, and booleans are compared by value.
        case '[object String]':
          // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
          // equivalent to `new String("5")`.
          return a == String(b);
        case '[object Number]':
          // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
          // other numeric values.
          return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
        case '[object Date]':
        case '[object Boolean]':
          // Coerce dates and booleans to numeric primitive values. Dates are compared by their
          // millisecond representations. Note that invalid dates with millisecond representations
          // of `NaN` are not equivalent.
          return +a == +b;
        // RegExps are compared by their source patterns and flags.
        case '[object RegExp]':
          return a.source == b.source &&
                 a.global == b.global &&
                 a.multiline == b.multiline &&
                 a.ignoreCase == b.ignoreCase;
      }
      if (typeof a != 'object' || typeof b != 'object') return false;
      // Assume equality for cyclic structures. The algorithm for detecting cyclic
      // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
      var length = aStack.length;
      while (length--) {
        // Linear search. Performance is inversely proportional to the number of
        // unique nested structures.
        if (aStack[length] == a) return bStack[length] == b;
      }
      // Add the first object to the stack of traversed objects.
      aStack.push(a);
      bStack.push(b);
      var size = 0, result = true;
      // Recursively compare objects and arrays.
      if (className == '[object Array]') {
        // Compare array lengths to determine if a deep comparison is necessary.
        size = a.length;
        result = size == b.length;
        if (result) {
          // Deep compare the contents, ignoring non-numeric properties.
          while (size--) {
            if (!(result = eq(a[size], b[size], aStack, bStack))) break;
          }
        }
      } else {
        // Objects with different constructors are not equivalent, but `Object`s
        // from different frames are.
        var aCtor = a.constructor, bCtor = b.constructor;
        if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
                                 _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
          return false;
        }
        // Deep compare objects.
        for (var key in a) {
          if (_.has(a, key)) {
            // Count the expected number of properties.
            size++;
            // Deep compare each member.
            if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
          }
        }
        // Ensure that both objects contain the same number of properties.
        if (result) {
          for (key in b) {
            if (_.has(b, key) && !(size--)) break;
          }
          result = !size;
        }
      }
      // Remove the first object from the stack of traversed objects.
      aStack.pop();
      bStack.pop();
      return result;
    };
  
    // Perform a deep comparison to check if two objects are equal.
    _.isEqual = function(a, b) {
      return eq(a, b, [], []);
    };
  
    // Is a given array, string, or object empty?
    // An "empty" object has no enumerable own-properties.
    _.isEmpty = function(obj) {
      if (obj == null) return true;
      if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
      for (var key in obj) if (_.has(obj, key)) return false;
      return true;
    };
  
    // Is a given value a DOM element?
    _.isElement = function(obj) {
      return !!(obj && obj.nodeType === 1);
    };
  
    // Is a given value an array?
    // Delegates to ECMA5's native Array.isArray
    _.isArray = nativeIsArray || function(obj) {
      return toString.call(obj) == '[object Array]';
    };
  
    // Is a given variable an object?
    _.isObject = function(obj) {
      return obj === Object(obj);
    };
  
    // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
    each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
      _['is' + name] = function(obj) {
        return toString.call(obj) == '[object ' + name + ']';
      };
    });
  
    // Define a fallback version of the method in browsers (ahem, IE), where
    // there isn't any inspectable "Arguments" type.
    if (!_.isArguments(arguments)) {
      _.isArguments = function(obj) {
        return !!(obj && _.has(obj, 'callee'));
      };
    }
  
    // Optimize `isFunction` if appropriate.
    if (typeof (/./) !== 'function') {
      _.isFunction = function(obj) {
        return typeof obj === 'function';
      };
    }
  
    // Is a given object a finite number?
    _.isFinite = function(obj) {
      return isFinite(obj) && !isNaN(parseFloat(obj));
    };
  
    // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    _.isNaN = function(obj) {
      return _.isNumber(obj) && obj != +obj;
    };
  
    // Is a given value a boolean?
    _.isBoolean = function(obj) {
      return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
    };
  
    // Is a given value equal to null?
    _.isNull = function(obj) {
      return obj === null;
    };
  
    // Is a given variable undefined?
    _.isUndefined = function(obj) {
      return obj === void 0;
    };
  
    // Shortcut function for checking if an object has a given property directly
    // on itself (in other words, not on a prototype).
    _.has = function(obj, key) {
      return hasOwnProperty.call(obj, key);
    };
  
    // Utility Functions
    // -----------------
  
    // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
    // previous owner. Returns a reference to the Underscore object.
    _.noConflict = function() {
      root._ = previousUnderscore;
      return this;
    };
  
    // Keep the identity function around for default iterators.
    _.identity = function(value) {
      return value;
    };
  
    // Run a function **n** times.
    _.times = function(n, iterator, context) {
      var accum = Array(n);
      for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
      return accum;
    };
  
    // Return a random integer between min and max (inclusive).
    _.random = function(min, max) {
      if (max == null) {
        max = min;
        min = 0;
      }
      return min + (0 | Math.random() * (max - min + 1));
    };
  
    // List of HTML entities for escaping.
    var entityMap = {
      escape: {
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#x27;',
        '/': '&#x2F;'
      }
    };
    entityMap.unescape = _.invert(entityMap.escape);
  
    // Regexes containing the keys and values listed immediately above.
    var entityRegexes = {
      escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
      unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
    };
  
    // Functions for escaping and unescaping strings to/from HTML interpolation.
    _.each(['escape', 'unescape'], function(method) {
      _[method] = function(string) {
        if (string == null) return '';
        return ('' + string).replace(entityRegexes[method], function(match) {
          return entityMap[method][match];
        });
      };
    });
  
    // If the value of the named property is a function then invoke it;
    // otherwise, return it.
    _.result = function(object, property) {
      if (object == null) return null;
      var value = object[property];
      return _.isFunction(value) ? value.call(object) : value;
    };
  
    // Add your own custom functions to the Underscore object.
    _.mixin = function(obj) {
      each(_.functions(obj), function(name){
        var func = _[name] = obj[name];
        _.prototype[name] = function() {
          var args = [this._wrapped];
          push.apply(args, arguments);
          return result.call(this, func.apply(_, args));
        };
      });
    };
  
    // Generate a unique integer id (unique within the entire client session).
    // Useful for temporary DOM ids.
    var idCounter = 0;
    _.uniqueId = function(prefix) {
      var id = '' + ++idCounter;
      return prefix ? prefix + id : id;
    };
  
    // By default, Underscore uses ERB-style template delimiters, change the
    // following template settings to use alternative delimiters.
    _.templateSettings = {
      evaluate    : /<%([\s\S]+?)%>/g,
      interpolate : /<%=([\s\S]+?)%>/g,
      escape      : /<%-([\s\S]+?)%>/g
    };
  
    // When customizing `templateSettings`, if you don't want to define an
    // interpolation, evaluation or escaping regex, we need one that is
    // guaranteed not to match.
    var noMatch = /(.)^/;
  
    // Certain characters need to be escaped so that they can be put into a
    // string literal.
    var escapes = {
      "'":      "'",
      '\\':     '\\',
      '\r':     'r',
      '\n':     'n',
      '\t':     't',
      '\u2028': 'u2028',
      '\u2029': 'u2029'
    };
  
    var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
  
    // JavaScript micro-templating, similar to John Resig's implementation.
    // Underscore templating handles arbitrary delimiters, preserves whitespace,
    // and correctly escapes quotes within interpolated code.
    _.template = function(text, data, settings) {
      settings = _.defaults({}, settings, _.templateSettings);
  
      // Combine delimiters into one regular expression via alternation.
      var matcher = new RegExp([
        (settings.escape || noMatch).source,
        (settings.interpolate || noMatch).source,
        (settings.evaluate || noMatch).source
      ].join('|') + '|$', 'g');
  
      // Compile the template source, escaping string literals appropriately.
      var index = 0;
      var source = "__p+='";
      text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
        source += text.slice(index, offset)
          .replace(escaper, function(match) { return '\\' + escapes[match]; });
  
        if (escape) {
          source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
        }
        if (interpolate) {
          source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
        }
        if (evaluate) {
          source += "';\n" + evaluate + "\n__p+='";
        }
        index = offset + match.length;
        return match;
      });
      source += "';\n";
  
      // If a variable is not specified, place data values in local scope.
      if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
  
      source = "var __t,__p='',__j=Array.prototype.join," +
        "print=function(){__p+=__j.call(arguments,'');};\n" +
        source + "return __p;\n";
  
      try {
        var render = new Function(settings.variable || 'obj', '_', source);
      } catch (e) {
        e.source = source;
        throw e;
      }
  
      if (data) return render(data, _);
      var template = function(data) {
        return render.call(this, data, _);
      };
  
      // Provide the compiled function source as a convenience for precompilation.
      template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
  
      return template;
    };
  
    // Add a "chain" function, which will delegate to the wrapper.
    _.chain = function(obj) {
      return _(obj).chain();
    };
  
    // OOP
    // ---------------
    // If Underscore is called as a function, it returns a wrapped object that
    // can be used OO-style. This wrapper holds altered versions of all the
    // underscore functions. Wrapped objects may be chained.
  
    // Helper function to continue chaining intermediate results.
    var result = function(obj) {
      return this._chain ? _(obj).chain() : obj;
    };
  
    // Add all of the Underscore functions to the wrapper object.
    _.mixin(_);
  
    // Add all mutator Array functions to the wrapper.
    each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
      var method = ArrayProto[name];
      _.prototype[name] = function() {
        var obj = this._wrapped;
        method.apply(obj, arguments);
        if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
        return result.call(this, obj);
      };
    });
  
    // Add all accessor Array functions to the wrapper.
    each(['concat', 'join', 'slice'], function(name) {
      var method = ArrayProto[name];
      _.prototype[name] = function() {
        return result.call(this, method.apply(this._wrapped, arguments));
      };
    });
  
    _.extend(_.prototype, {
  
      // Start chaining a wrapped Underscore object.
      chain: function() {
        this._chain = true;
        return this;
      },
  
      // Extracts the result from a wrapped and chained object.
      value: function() {
        return this._wrapped;
      }
  
    });
  
  }).call(this);
  //     Backbone.js 0.9.10
  
  //     (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
  //     Backbone may be freely distributed under the MIT license.
  //     For all details and documentation:
  //     http://backbonejs.org
  
  (function(){
  
    // Initial Setup
    // -------------
  
    // Save a reference to the global object (`window` in the browser, `exports`
    // on the server).
    var root = this;
  
    // Save the previous value of the `Backbone` variable, so that it can be
    // restored later on, if `noConflict` is used.
    var previousBackbone = root.Backbone;
  
    // Create a local reference to array methods.
    var array = [];
    var push = array.push;
    var slice = array.slice;
    var splice = array.splice;
  
    // The top-level namespace. All public Backbone classes and modules will
    // be attached to this. Exported for both CommonJS and the browser.
    var Backbone;
    if (typeof exports !== 'undefined') {
      Backbone = exports;
    } else {
      Backbone = root.Backbone = {};
    }
  
    // Current version of the library. Keep in sync with `package.json`.
    Backbone.VERSION = '0.9.10';
  
    // Require Underscore, if we're on the server, and it's not already present.
    var _ = root._;
    if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
  
    // For Backbone's purposes, jQuery, Zepto, or Ender owns the `$` variable.
    Backbone.$ = root.jQuery || root.Zepto || root.ender;
  
    // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
    // to its previous owner. Returns a reference to this Backbone object.
    Backbone.noConflict = function() {
      root.Backbone = previousBackbone;
      return this;
    };
  
    // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
    // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
    // set a `X-Http-Method-Override` header.
    Backbone.emulateHTTP = false;
  
    // Turn on `emulateJSON` to support legacy servers that can't deal with direct
    // `application/json` requests ... will encode the body as
    // `application/x-www-form-urlencoded` instead and will send the model in a
    // form param named `model`.
    Backbone.emulateJSON = false;
  
    // Backbone.Events
    // ---------------
  
    // Regular expression used to split event strings.
    var eventSplitter = /\s+/;
  
    // Implement fancy features of the Events API such as multiple event
    // names `"change blur"` and jQuery-style event maps `{change: action}`
    // in terms of the existing API.
    var eventsApi = function(obj, action, name, rest) {
      if (!name) return true;
      if (typeof name === 'object') {
        for (var key in name) {
          obj[action].apply(obj, [key, name[key]].concat(rest));
        }
      } else if (eventSplitter.test(name)) {
        var names = name.split(eventSplitter);
        for (var i = 0, l = names.length; i < l; i++) {
          obj[action].apply(obj, [names[i]].concat(rest));
        }
      } else {
        return true;
      }
    };
  
    // Optimized internal dispatch function for triggering events. Tries to
    // keep the usual cases speedy (most Backbone events have 3 arguments).
    var triggerEvents = function(events, args) {
      var ev, i = -1, l = events.length;
      switch (args.length) {
      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx);
      return;
      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0]);
      return;
      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1]);
      return;
      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, args[0], args[1], args[2]);
      return;
      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
      }
    };
  
    // A module that can be mixed in to *any object* in order to provide it with
    // custom events. You may bind with `on` or remove with `off` callback
    // functions to an event; `trigger`-ing an event fires all callbacks in
    // succession.
    //
    //     var object = {};
    //     _.extend(object, Backbone.Events);
    //     object.on('expand', function(){ alert('expanded'); });
    //     object.trigger('expand');
    //
    var Events = Backbone.Events = {
  
      // Bind one or more space separated events, or an events map,
      // to a `callback` function. Passing `"all"` will bind the callback to
      // all events fired.
      on: function(name, callback, context) {
        if (!(eventsApi(this, 'on', name, [callback, context]) && callback)) return this;
        this._events || (this._events = {});
        var list = this._events[name] || (this._events[name] = []);
        list.push({callback: callback, context: context, ctx: context || this});
        return this;
      },
  
      // Bind events to only be triggered a single time. After the first time
      // the callback is invoked, it will be removed.
      once: function(name, callback, context) {
        if (!(eventsApi(this, 'once', name, [callback, context]) && callback)) return this;
        var self = this;
        var once = _.once(function() {
          self.off(name, once);
          callback.apply(this, arguments);
        });
        once._callback = callback;
        this.on(name, once, context);
        return this;
      },
  
      // Remove one or many callbacks. If `context` is null, removes all
      // callbacks with that function. If `callback` is null, removes all
      // callbacks for the event. If `name` is null, removes all bound
      // callbacks for all events.
      off: function(name, callback, context) {
        var list, ev, events, names, i, l, j, k;
        if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
        if (!name && !callback && !context) {
          this._events = {};
          return this;
        }
  
        names = name ? [name] : _.keys(this._events);
        for (i = 0, l = names.length; i < l; i++) {
          name = names[i];
          if (list = this._events[name]) {
            events = [];
            if (callback || context) {
              for (j = 0, k = list.length; j < k; j++) {
                ev = list[j];
                if ((callback && callback !== ev.callback &&
                                 callback !== ev.callback._callback) ||
                    (context && context !== ev.context)) {
                  events.push(ev);
                }
              }
            }
            this._events[name] = events;
          }
        }
  
        return this;
      },
  
      // Trigger one or many events, firing all bound callbacks. Callbacks are
      // passed the same arguments as `trigger` is, apart from the event name
      // (unless you're listening on `"all"`, which will cause your callback to
      // receive the true name of the event as the first argument).
      trigger: function(name) {
        if (!this._events) return this;
        var args = slice.call(arguments, 1);
        if (!eventsApi(this, 'trigger', name, args)) return this;
        var events = this._events[name];
        var allEvents = this._events.all;
        if (events) triggerEvents(events, args);
        if (allEvents) triggerEvents(allEvents, arguments);
        return this;
      },
  
      // An inversion-of-control version of `on`. Tell *this* object to listen to
      // an event in another object ... keeping track of what it's listening to.
      listenTo: function(obj, name, callback) {
        var listeners = this._listeners || (this._listeners = {});
        var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
        listeners[id] = obj;
        obj.on(name, typeof name === 'object' ? this : callback, this);
        return this;
      },
  
      // Tell this object to stop listening to either specific events ... or
      // to every object it's currently listening to.
      stopListening: function(obj, name, callback) {
        var listeners = this._listeners;
        if (!listeners) return;
        if (obj) {
          obj.off(name, typeof name === 'object' ? this : callback, this);
          if (!name && !callback) delete listeners[obj._listenerId];
        } else {
          if (typeof name === 'object') callback = this;
          for (var id in listeners) {
            listeners[id].off(name, callback, this);
          }
          this._listeners = {};
        }
        return this;
      }
    };
  
    // Aliases for backwards compatibility.
    Events.bind   = Events.on;
    Events.unbind = Events.off;
  
    // Allow the `Backbone` object to serve as a global event bus, for folks who
    // want global "pubsub" in a convenient place.
    _.extend(Backbone, Events);
  
    // Backbone.Model
    // --------------
  
    // Create a new model, with defined attributes. A client id (`cid`)
    // is automatically generated and assigned for you.
    var Model = Backbone.Model = function(attributes, options) {
      var defaults;
      var attrs = attributes || {};
      this.cid = _.uniqueId('c');
      this.attributes = {};
      if (options && options.collection) this.collection = options.collection;
      if (options && options.parse) attrs = this.parse(attrs, options) || {};
      if (defaults = _.result(this, 'defaults')) {
        attrs = _.defaults({}, attrs, defaults);
      }
      this.set(attrs, options);
      this.changed = {};
      this.initialize.apply(this, arguments);
    };
  
    // Attach all inheritable methods to the Model prototype.
    _.extend(Model.prototype, Events, {
  
      // A hash of attributes whose current and previous value differ.
      changed: null,
  
      // The default name for the JSON `id` attribute is `"id"`. MongoDB and
      // CouchDB users may want to set this to `"_id"`.
      idAttribute: 'id',
  
      // Initialize is an empty function by default. Override it with your own
      // initialization logic.
      initialize: function(){},
  
      // Return a copy of the model's `attributes` object.
      toJSON: function(options) {
        return _.clone(this.attributes);
      },
  
      // Proxy `Backbone.sync` by default.
      sync: function() {
        return Backbone.sync.apply(this, arguments);
      },
  
      // Get the value of an attribute.
      get: function(attr) {
        return this.attributes[attr];
      },
  
      // Get the HTML-escaped value of an attribute.
      escape: function(attr) {
        return _.escape(this.get(attr));
      },
  
      // Returns `true` if the attribute contains a value that is not null
      // or undefined.
      has: function(attr) {
        return this.get(attr) != null;
      },
  
      // ----------------------------------------------------------------------
  
      // Set a hash of model attributes on the object, firing `"change"` unless
      // you choose to silence it.
      set: function(key, val, options) {
        var attr, attrs, unset, changes, silent, changing, prev, current;
        if (key == null) return this;
  
        // Handle both `"key", value` and `{key: value}` -style arguments.
        if (typeof key === 'object') {
          attrs = key;
          options = val;
        } else {
          (attrs = {})[key] = val;
        }
  
        options || (options = {});
  
        // Run validation.
        if (!this._validate(attrs, options)) return false;
  
        // Extract attributes and options.
        unset           = options.unset;
        silent          = options.silent;
        changes         = [];
        changing        = this._changing;
        this._changing  = true;
  
        if (!changing) {
          this._previousAttributes = _.clone(this.attributes);
          this.changed = {};
        }
        current = this.attributes, prev = this._previousAttributes;
  
        // Check for changes of `id`.
        if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
  
        // For each `set` attribute, update or delete the current value.
        for (attr in attrs) {
          val = attrs[attr];
          if (!_.isEqual(current[attr], val)) changes.push(attr);
          if (!_.isEqual(prev[attr], val)) {
            this.changed[attr] = val;
          } else {
            delete this.changed[attr];
          }
          unset ? delete current[attr] : current[attr] = val;
        }
  
        // Trigger all relevant attribute changes.
        if (!silent) {
          if (changes.length) this._pending = true;
          for (var i = 0, l = changes.length; i < l; i++) {
            this.trigger('change:' + changes[i], this, current[changes[i]], options);
          }
        }
  
        if (changing) return this;
        if (!silent) {
          while (this._pending) {
            this._pending = false;
            this.trigger('change', this, options);
          }
        }
        this._pending = false;
        this._changing = false;
        return this;
      },
  
      // Remove an attribute from the model, firing `"change"` unless you choose
      // to silence it. `unset` is a noop if the attribute doesn't exist.
      unset: function(attr, options) {
        return this.set(attr, void 0, _.extend({}, options, {unset: true}));
      },
  
      // Clear all attributes on the model, firing `"change"` unless you choose
      // to silence it.
      clear: function(options) {
        var attrs = {};
        for (var key in this.attributes) attrs[key] = void 0;
        return this.set(attrs, _.extend({}, options, {unset: true}));
      },
  
      // Determine if the model has changed since the last `"change"` event.
      // If you specify an attribute name, determine if that attribute has changed.
      hasChanged: function(attr) {
        if (attr == null) return !_.isEmpty(this.changed);
        return _.has(this.changed, attr);
      },
  
      // Return an object containing all the attributes that have changed, or
      // false if there are no changed attributes. Useful for determining what
      // parts of a view need to be updated and/or what attributes need to be
      // persisted to the server. Unset attributes will be set to undefined.
      // You can also pass an attributes object to diff against the model,
      // determining if there *would be* a change.
      changedAttributes: function(diff) {
        if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
        var val, changed = false;
        var old = this._changing ? this._previousAttributes : this.attributes;
        for (var attr in diff) {
          if (_.isEqual(old[attr], (val = diff[attr]))) continue;
          (changed || (changed = {}))[attr] = val;
        }
        return changed;
      },
  
      // Get the previous value of an attribute, recorded at the time the last
      // `"change"` event was fired.
      previous: function(attr) {
        if (attr == null || !this._previousAttributes) return null;
        return this._previousAttributes[attr];
      },
  
      // Get all of the attributes of the model at the time of the previous
      // `"change"` event.
      previousAttributes: function() {
        return _.clone(this._previousAttributes);
      },
  
      // ---------------------------------------------------------------------
  
      // Fetch the model from the server. If the server's representation of the
      // model differs from its current attributes, they will be overriden,
      // triggering a `"change"` event.
      fetch: function(options) {
        options = options ? _.clone(options) : {};
        if (options.parse === void 0) options.parse = true;
        var success = options.success;
        options.success = function(model, resp, options) {
          if (!model.set(model.parse(resp, options), options)) return false;
          if (success) success(model, resp, options);
        };
        return this.sync('read', this, options);
      },
  
      // Set a hash of model attributes, and sync the model to the server.
      // If the server returns an attributes hash that differs, the model's
      // state will be `set` again.
      save: function(key, val, options) {
        var attrs, success, method, xhr, attributes = this.attributes;
  
        // Handle both `"key", value` and `{key: value}` -style arguments.
        if (key == null || typeof key === 'object') {
          attrs = key;
          options = val;
        } else {
          (attrs = {})[key] = val;
        }
  
        // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
        if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
  
        options = _.extend({validate: true}, options);
  
        // Do not persist invalid models.
        if (!this._validate(attrs, options)) return false;
  
        // Set temporary attributes if `{wait: true}`.
        if (attrs && options.wait) {
          this.attributes = _.extend({}, attributes, attrs);
        }
  
        // After a successful server-side save, the client is (optionally)
        // updated with the server-side state.
        if (options.parse === void 0) options.parse = true;
        success = options.success;
        options.success = function(model, resp, options) {
          // Ensure attributes are restored during synchronous saves.
          model.attributes = attributes;
          var serverAttrs = model.parse(resp, options);
          if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
          if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
            return false;
          }
          if (success) success(model, resp, options);
        };
  
        // Finish configuring and sending the Ajax request.
        method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
        if (method === 'patch') options.attrs = attrs;
        xhr = this.sync(method, this, options);
  
        // Restore attributes.
        if (attrs && options.wait) this.attributes = attributes;
  
        return xhr;
      },
  
      // Destroy this model on the server if it was already persisted.
      // Optimistically removes the model from its collection, if it has one.
      // If `wait: true` is passed, waits for the server to respond before removal.
      destroy: function(options) {
        options = options ? _.clone(options) : {};
        var model = this;
        var success = options.success;
  
        var destroy = function() {
          model.trigger('destroy', model, model.collection, options);
        };
  
        options.success = function(model, resp, options) {
          if (options.wait || model.isNew()) destroy();
          if (success) success(model, resp, options);
        };
  
        if (this.isNew()) {
          options.success(this, null, options);
          return false;
        }
  
        var xhr = this.sync('delete', this, options);
        if (!options.wait) destroy();
        return xhr;
      },
  
      // Default URL for the model's representation on the server -- if you're
      // using Backbone's restful methods, override this to change the endpoint
      // that will be called.
      url: function() {
        var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
        if (this.isNew()) return base;
        return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
      },
  
      // **parse** converts a response into the hash of attributes to be `set` on
      // the model. The default implementation is just to pass the response along.
      parse: function(resp, options) {
        return resp;
      },
  
      // Create a new model with identical attributes to this one.
      clone: function() {
        return new this.constructor(this.attributes);
      },
  
      // A model is new if it has never been saved to the server, and lacks an id.
      isNew: function() {
        return this.id == null;
      },
  
      // Check if the model is currently in a valid state.
      isValid: function(options) {
        return !this.validate || !this.validate(this.attributes, options);
      },
  
      // Run validation against the next complete set of model attributes,
      // returning `true` if all is well. Otherwise, fire a general
      // `"error"` event and call the error callback, if specified.
      _validate: function(attrs, options) {
        if (!options.validate || !this.validate) return true;
        attrs = _.extend({}, this.attributes, attrs);
        var error = this.validationError = this.validate(attrs, options) || null;
        if (!error) return true;
        this.trigger('invalid', this, error, options || {});
        return false;
      }
  
    });
  
    // Backbone.Collection
    // -------------------
  
    // Provides a standard collection class for our sets of models, ordered
    // or unordered. If a `comparator` is specified, the Collection will maintain
    // its models in sort order, as they're added and removed.
    var Collection = Backbone.Collection = function(models, options) {
      options || (options = {});
      if (options.model) this.model = options.model;
      if (options.comparator !== void 0) this.comparator = options.comparator;
      this.models = [];
      this._reset();
      this.initialize.apply(this, arguments);
      if (models) this.reset(models, _.extend({silent: true}, options));
    };
  
    // Define the Collection's inheritable methods.
    _.extend(Collection.prototype, Events, {
  
      // The default model for a collection is just a **Backbone.Model**.
      // This should be overridden in most cases.
      model: Model,
  
      // Initialize is an empty function by default. Override it with your own
      // initialization logic.
      initialize: function(){},
  
      // The JSON representation of a Collection is an array of the
      // models' attributes.
      toJSON: function(options) {
        return this.map(function(model){ return model.toJSON(options); });
      },
  
      // Proxy `Backbone.sync` by default.
      sync: function() {
        return Backbone.sync.apply(this, arguments);
      },
  
      // Add a model, or list of models to the set.
      add: function(models, options) {
        models = _.isArray(models) ? models.slice() : [models];
        options || (options = {});
        var i, l, model, attrs, existing, doSort, add, at, sort, sortAttr;
        add = [];
        at = options.at;
        sort = this.comparator && (at == null) && options.sort != false;
        sortAttr = _.isString(this.comparator) ? this.comparator : null;
  
        // Turn bare objects into model references, and prevent invalid models
        // from being added.
        for (i = 0, l = models.length; i < l; i++) {
          if (!(model = this._prepareModel(attrs = models[i], options))) {
            this.trigger('invalid', this, attrs, options);
            continue;
          }
  
          // If a duplicate is found, prevent it from being added and
          // optionally merge it into the existing model.
          if (existing = this.get(model)) {
            if (options.merge) {
              existing.set(attrs === model ? model.attributes : attrs, options);
              if (sort && !doSort && existing.hasChanged(sortAttr)) doSort = true;
            }
            continue;
          }
  
          // This is a new model, push it to the `add` list.
          add.push(model);
  
          // Listen to added models' events, and index models for lookup by
          // `id` and by `cid`.
          model.on('all', this._onModelEvent, this);
          this._byId[model.cid] = model;
          if (model.id != null) this._byId[model.id] = model;
        }
  
        // See if sorting is needed, update `length` and splice in new models.
        if (add.length) {
          if (sort) doSort = true;
          this.length += add.length;
          if (at != null) {
            splice.apply(this.models, [at, 0].concat(add));
          } else {
            push.apply(this.models, add);
          }
        }
  
        // Silently sort the collection if appropriate.
        if (doSort) this.sort({silent: true});
  
        if (options.silent) return this;
  
        // Trigger `add` events.
        for (i = 0, l = add.length; i < l; i++) {
          (model = add[i]).trigger('add', model, this, options);
        }
  
        // Trigger `sort` if the collection was sorted.
        if (doSort) this.trigger('sort', this, options);
  
        return this;
      },
  
      // Remove a model, or a list of models from the set.
      remove: function(models, options) {
        models = _.isArray(models) ? models.slice() : [models];
        options || (options = {});
        var i, l, index, model;
        for (i = 0, l = models.length; i < l; i++) {
          model = this.get(models[i]);
          if (!model) continue;
          delete this._byId[model.id];
          delete this._byId[model.cid];
          index = this.indexOf(model);
          this.models.splice(index, 1);
          this.length--;
          if (!options.silent) {
            options.index = index;
            model.trigger('remove', model, this, options);
          }
          this._removeReference(model);
        }
        return this;
      },
  
      // Add a model to the end of the collection.
      push: function(model, options) {
        model = this._prepareModel(model, options);
        this.add(model, _.extend({at: this.length}, options));
        return model;
      },
  
      // Remove a model from the end of the collection.
      pop: function(options) {
        var model = this.at(this.length - 1);
        this.remove(model, options);
        return model;
      },
  
      // Add a model to the beginning of the collection.
      unshift: function(model, options) {
        model = this._prepareModel(model, options);
        this.add(model, _.extend({at: 0}, options));
        return model;
      },
  
      // Remove a model from the beginning of the collection.
      shift: function(options) {
        var model = this.at(0);
        this.remove(model, options);
        return model;
      },
  
      // Slice out a sub-array of models from the collection.
      slice: function(begin, end) {
        return this.models.slice(begin, end);
      },
  
      // Get a model from the set by id.
      get: function(obj) {
        if (obj == null) return void 0;
        this._idAttr || (this._idAttr = this.model.prototype.idAttribute);
        return this._byId[obj.id || obj.cid || obj[this._idAttr] || obj];
      },
  
      // Get the model at the given index.
      at: function(index) {
        return this.models[index];
      },
  
      // Return models with matching attributes. Useful for simple cases of `filter`.
      where: function(attrs) {
        if (_.isEmpty(attrs)) return [];
        return this.filter(function(model) {
          for (var key in attrs) {
            if (attrs[key] !== model.get(key)) return false;
          }
          return true;
        });
      },
  
      // Force the collection to re-sort itself. You don't need to call this under
      // normal circumstances, as the set will maintain sort order as each item
      // is added.
      sort: function(options) {
        if (!this.comparator) {
          throw new Error('Cannot sort a set without a comparator');
        }
        options || (options = {});
  
        // Run sort based on type of `comparator`.
        if (_.isString(this.comparator) || this.comparator.length === 1) {
          this.models = this.sortBy(this.comparator, this);
        } else {
          this.models.sort(_.bind(this.comparator, this));
        }
  
        if (!options.silent) this.trigger('sort', this, options);
        return this;
      },
  
      // Pluck an attribute from each model in the collection.
      pluck: function(attr) {
        return _.invoke(this.models, 'get', attr);
      },
  
      // Smartly update a collection with a change set of models, adding,
      // removing, and merging as necessary.
      update: function(models, options) {
        options = _.extend({add: true, merge: true, remove: true}, options);
        if (options.parse) models = this.parse(models, options);
        var model, i, l, existing;
        var add = [], remove = [], modelMap = {};
  
        // Allow a single model (or no argument) to be passed.
        if (!_.isArray(models)) models = models ? [models] : [];
  
        // Proxy to `add` for this case, no need to iterate...
        if (options.add && !options.remove) return this.add(models, options);
  
        // Determine which models to add and merge, and which to remove.
        for (i = 0, l = models.length; i < l; i++) {
          model = models[i];
          existing = this.get(model);
          if (options.remove && existing) modelMap[existing.cid] = true;
          if ((options.add && !existing) || (options.merge && existing)) {
            add.push(model);
          }
        }
        if (options.remove) {
          for (i = 0, l = this.models.length; i < l; i++) {
            model = this.models[i];
            if (!modelMap[model.cid]) remove.push(model);
          }
        }
  
        // Remove models (if applicable) before we add and merge the rest.
        if (remove.length) this.remove(remove, options);
        if (add.length) this.add(add, options);
        return this;
      },
  
      // When you have more items than you want to add or remove individually,
      // you can reset the entire set with a new list of models, without firing
      // any `add` or `remove` events. Fires `reset` when finished.
      reset: function(models, options) {
        options || (options = {});
        if (options.parse) models = this.parse(models, options);
        for (var i = 0, l = this.models.length; i < l; i++) {
          this._removeReference(this.models[i]);
        }
        options.previousModels = this.models.slice();
        this._reset();
        if (models) this.add(models, _.extend({silent: true}, options));
        if (!options.silent) this.trigger('reset', this, options);
        return this;
      },
  
      // Fetch the default set of models for this collection, resetting the
      // collection when they arrive. If `update: true` is passed, the response
      // data will be passed through the `update` method instead of `reset`.
      fetch: function(options) {
        options = options ? _.clone(options) : {};
        if (options.parse === void 0) options.parse = true;
        var success = options.success;
        options.success = function(collection, resp, options) {
          var method = options.update ? 'update' : 'reset';
          collection[method](resp, options);
          if (success) success(collection, resp, options);
        };
        return this.sync('read', this, options);
      },
  
      // Create a new instance of a model in this collection. Add the model to the
      // collection immediately, unless `wait: true` is passed, in which case we
      // wait for the server to agree.
      create: function(model, options) {
        options = options ? _.clone(options) : {};
        if (!(model = this._prepareModel(model, options))) return false;
        if (!options.wait) this.add(model, options);
        var collection = this;
        var success = options.success;
        options.success = function(model, resp, options) {
          if (options.wait) collection.add(model, options);
          if (success) success(model, resp, options);
        };
        model.save(null, options);
        return model;
      },
  
      // **parse** converts a response into a list of models to be added to the
      // collection. The default implementation is just to pass it through.
      parse: function(resp, options) {
        return resp;
      },
  
      // Create a new collection with an identical list of models as this one.
      clone: function() {
        return new this.constructor(this.models);
      },
  
      // Reset all internal state. Called when the collection is reset.
      _reset: function() {
        this.length = 0;
        this.models.length = 0;
        this._byId  = {};
      },
  
      // Prepare a model or hash of attributes to be added to this collection.
      _prepareModel: function(attrs, options) {
        if (attrs instanceof Model) {
          if (!attrs.collection) attrs.collection = this;
          return attrs;
        }
        options || (options = {});
        options.collection = this;
        var model = new this.model(attrs, options);
        if (!model._validate(attrs, options)) return false;
        return model;
      },
  
      // Internal method to remove a model's ties to a collection.
      _removeReference: function(model) {
        if (this === model.collection) delete model.collection;
        model.off('all', this._onModelEvent, this);
      },
  
      // Internal method called every time a model in the set fires an event.
      // Sets need to update their indexes when models change ids. All other
      // events simply proxy through. "add" and "remove" events that originate
      // in other collections are ignored.
      _onModelEvent: function(event, model, collection, options) {
        if ((event === 'add' || event === 'remove') && collection !== this) return;
        if (event === 'destroy') this.remove(model, options);
        if (model && event === 'change:' + model.idAttribute) {
          delete this._byId[model.previous(model.idAttribute)];
          if (model.id != null) this._byId[model.id] = model;
        }
        this.trigger.apply(this, arguments);
      },
  
      sortedIndex: function (model, value, context) {
        value || (value = this.comparator);
        var iterator = _.isFunction(value) ? value : function(model) {
          return model.get(value);
        };
        return _.sortedIndex(this.models, model, iterator, context);
      }
  
    });
  
    // Underscore methods that we want to implement on the Collection.
    var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
      'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
      'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
      'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
      'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
      'isEmpty', 'chain'];
  
    // Mix in each Underscore method as a proxy to `Collection#models`.
    _.each(methods, function(method) {
      Collection.prototype[method] = function() {
        var args = slice.call(arguments);
        args.unshift(this.models);
        return _[method].apply(_, args);
      };
    });
  
    // Underscore methods that take a property name as an argument.
    var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
  
    // Use attributes instead of properties.
    _.each(attributeMethods, function(method) {
      Collection.prototype[method] = function(value, context) {
        var iterator = _.isFunction(value) ? value : function(model) {
          return model.get(value);
        };
        return _[method](this.models, iterator, context);
      };
    });
  
    // Backbone.Router
    // ---------------
  
    // Routers map faux-URLs to actions, and fire events when routes are
    // matched. Creating a new one sets its `routes` hash, if not set statically.
    var Router = Backbone.Router = function(options) {
      options || (options = {});
      if (options.routes) this.routes = options.routes;
      this._bindRoutes();
      this.initialize.apply(this, arguments);
    };
  
    // Cached regular expressions for matching named param parts and splatted
    // parts of route strings.
    var optionalParam = /\((.*?)\)/g;
    var namedParam    = /(\(\?)?:\w+/g;
    var splatParam    = /\*\w+/g;
    var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
  
    // Set up all inheritable **Backbone.Router** properties and methods.
    _.extend(Router.prototype, Events, {
  
      // Initialize is an empty function by default. Override it with your own
      // initialization logic.
      initialize: function(){},
  
      // Manually bind a single named route to a callback. For example:
      //
      //     this.route('search/:query/p:num', 'search', function(query, num) {
      //       ...
      //     });
      //
      route: function(route, name, callback) {
        if (!_.isRegExp(route)) route = this._routeToRegExp(route);
        if (!callback) callback = this[name];
        Backbone.history.route(route, _.bind(function(fragment) {
          var args = this._extractParameters(route, fragment);
          callback && callback.apply(this, args);
          this.trigger.apply(this, ['route:' + name].concat(args));
          this.trigger('route', name, args);
          Backbone.history.trigger('route', this, name, args);
        }, this));
        return this;
      },
  
      // Simple proxy to `Backbone.history` to save a fragment into the history.
      navigate: function(fragment, options) {
        Backbone.history.navigate(fragment, options);
        return this;
      },
  
      // Bind all defined routes to `Backbone.history`. We have to reverse the
      // order of the routes here to support behavior where the most general
      // routes can be defined at the bottom of the route map.
      _bindRoutes: function() {
        if (!this.routes) return;
        var route, routes = _.keys(this.routes);
        while ((route = routes.pop()) != null) {
          this.route(route, this.routes[route]);
        }
      },
  
      // Convert a route string into a regular expression, suitable for matching
      // against the current location hash.
      _routeToRegExp: function(route) {
        route = route.replace(escapeRegExp, '\\$&')
                     .replace(optionalParam, '(?:$1)?')
                     .replace(namedParam, function(match, optional){
                       return optional ? match : '([^\/]+)';
                     })
                     .replace(splatParam, '(.*?)');
        return new RegExp('^' + route + '$');
      },
  
      // Given a route, and a URL fragment that it matches, return the array of
      // extracted parameters.
      _extractParameters: function(route, fragment) {
        return route.exec(fragment).slice(1);
      }
  
    });
  
    // Backbone.History
    // ----------------
  
    // Handles cross-browser history management, based on URL fragments. If the
    // browser does not support `onhashchange`, falls back to polling.
    var History = Backbone.History = function() {
      this.handlers = [];
      _.bindAll(this, 'checkUrl');
  
      // Ensure that `History` can be used outside of the browser.
      if (typeof window !== 'undefined') {
        this.location = window.location;
        this.history = window.history;
      }
    };
  
    // Cached regex for stripping a leading hash/slash and trailing space.
    var routeStripper = /^[#\/]|\s+$/g;
  
    // Cached regex for stripping leading and trailing slashes.
    var rootStripper = /^\/+|\/+$/g;
  
    // Cached regex for detecting MSIE.
    var isExplorer = /msie [\w.]+/;
  
    // Cached regex for removing a trailing slash.
    var trailingSlash = /\/$/;
  
    // Has the history handling already been started?
    History.started = false;
  
    // Set up all inheritable **Backbone.History** properties and methods.
    _.extend(History.prototype, Events, {
  
      // The default interval to poll for hash changes, if necessary, is
      // twenty times a second.
      interval: 50,
  
      // Gets the true hash value. Cannot use location.hash directly due to bug
      // in Firefox where location.hash will always be decoded.
      getHash: function(window) {
        var match = (window || this).location.href.match(/#(.*)$/);
        return match ? match[1] : '';
      },
  
      // Get the cross-browser normalized URL fragment, either from the URL,
      // the hash, or the override.
      getFragment: function(fragment, forcePushState) {
        if (fragment == null) {
          if (this._hasPushState || !this._wantsHashChange || forcePushState) {
            fragment = this.location.pathname;
            var root = this.root.replace(trailingSlash, '');
            if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
          } else {
            fragment = this.getHash();
          }
        }
        return fragment.replace(routeStripper, '');
      },
  
      // Start the hash change handling, returning `true` if the current URL matches
      // an existing route, and `false` otherwise.
      start: function(options) {
        if (History.started) throw new Error("Backbone.history has already been started");
        History.started = true;
  
        // Figure out the initial configuration. Do we need an iframe?
        // Is pushState desired ... is it available?
        this.options          = _.extend({}, {root: '/'}, this.options, options);
        this.root             = this.options.root;
        this._wantsHashChange = this.options.hashChange !== false;
        this._wantsPushState  = !!this.options.pushState;
        this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
        var fragment          = this.getFragment();
        var docMode           = document.documentMode;
        var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
  
        // Normalize root to always include a leading and trailing slash.
        this.root = ('/' + this.root + '/').replace(rootStripper, '/');
  
        if (oldIE && this._wantsHashChange) {
          this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
          this.navigate(fragment);
        }
  
        // Depending on whether we're using pushState or hashes, and whether
        // 'onhashchange' is supported, determine how we check the URL state.
        if (this._hasPushState) {
          Backbone.$(window).on('popstate', this.checkUrl);
        } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
          Backbone.$(window).on('hashchange', this.checkUrl);
        } else if (this._wantsHashChange) {
          this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
        }
  
        // Determine if we need to change the base url, for a pushState link
        // opened by a non-pushState browser.
        this.fragment = fragment;
        var loc = this.location;
        var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
  
        // If we've started off with a route from a `pushState`-enabled browser,
        // but we're currently in a browser that doesn't support it...
        if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
          this.fragment = this.getFragment(null, true);
          this.location.replace(this.root + this.location.search + '#' + this.fragment);
          // Return immediately as browser will do redirect to new url
          return true;
  
        // Or if we've started out with a hash-based route, but we're currently
        // in a browser where it could be `pushState`-based instead...
        } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
          this.fragment = this.getHash().replace(routeStripper, '');
          this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
        }
  
        if (!this.options.silent) return this.loadUrl();
      },
  
      // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
      // but possibly useful for unit testing Routers.
      stop: function() {
        Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
        clearInterval(this._checkUrlInterval);
        History.started = false;
      },
  
      // Add a route to be tested when the fragment changes. Routes added later
      // may override previous routes.
      route: function(route, callback) {
        this.handlers.unshift({route: route, callback: callback});
      },
  
      // Checks the current URL to see if it has changed, and if it has,
      // calls `loadUrl`, normalizing across the hidden iframe.
      checkUrl: function(e) {
        var current = this.getFragment();
        if (current === this.fragment && this.iframe) {
          current = this.getFragment(this.getHash(this.iframe));
        }
        if (current === this.fragment) return false;
        if (this.iframe) this.navigate(current);
        this.loadUrl() || this.loadUrl(this.getHash());
      },
  
      // Attempt to load the current URL fragment. If a route succeeds with a
      // match, returns `true`. If no defined routes matches the fragment,
      // returns `false`.
      loadUrl: function(fragmentOverride) {
        var fragment = this.fragment = this.getFragment(fragmentOverride);
        var matched = _.any(this.handlers, function(handler) {
          if (handler.route.test(fragment)) {
            handler.callback(fragment);
            return true;
          }
        });
        return matched;
      },
  
      // Save a fragment into the hash history, or replace the URL state if the
      // 'replace' option is passed. You are responsible for properly URL-encoding
      // the fragment in advance.
      //
      // The options object can contain `trigger: true` if you wish to have the
      // route callback be fired (not usually desirable), or `replace: true`, if
      // you wish to modify the current URL without adding an entry to the history.
      navigate: function(fragment, options) {
        if (!History.started) return false;
        if (!options || options === true) options = {trigger: options};
        fragment = this.getFragment(fragment || '');
        if (this.fragment === fragment) return;
        this.fragment = fragment;
        var url = this.root + fragment;
  
        // If pushState is available, we use it to set the fragment as a real URL.
        if (this._hasPushState) {
          this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
  
        // If hash changes haven't been explicitly disabled, update the hash
        // fragment to store history.
        } else if (this._wantsHashChange) {
          this._updateHash(this.location, fragment, options.replace);
          if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
            // Opening and closing the iframe tricks IE7 and earlier to push a
            // history entry on hash-tag change.  When replace is true, we don't
            // want this.
            if(!options.replace) this.iframe.document.open().close();
            this._updateHash(this.iframe.location, fragment, options.replace);
          }
  
        // If you've told us that you explicitly don't want fallback hashchange-
        // based history, then `navigate` becomes a page refresh.
        } else {
          return this.location.assign(url);
        }
        if (options.trigger) this.loadUrl(fragment);
      },
  
      // Update the hash location, either replacing the current entry, or adding
      // a new one to the browser history.
      _updateHash: function(location, fragment, replace) {
        if (replace) {
          var href = location.href.replace(/(javascript:|#).*$/, '');
          location.replace(href + '#' + fragment);
        } else {
          // Some browsers require that `hash` contains a leading #.
          location.hash = '#' + fragment;
        }
      }
  
    });
  
    // Create the default Backbone.history.
    Backbone.history = new History;
  
    // Backbone.View
    // -------------
  
    // Creating a Backbone.View creates its initial element outside of the DOM,
    // if an existing element is not provided...
    var View = Backbone.View = function(options) {
      this.cid = _.uniqueId('view');
      this._configure(options || {});
      this._ensureElement();
      this.initialize.apply(this, arguments);
      this.delegateEvents();
    };
  
    // Cached regex to split keys for `delegate`.
    var delegateEventSplitter = /^(\S+)\s*(.*)$/;
  
    // List of view options to be merged as properties.
    var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
  
    // Set up all inheritable **Backbone.View** properties and methods.
    _.extend(View.prototype, Events, {
  
      // The default `tagName` of a View's element is `"div"`.
      tagName: 'div',
  
      // jQuery delegate for element lookup, scoped to DOM elements within the
      // current view. This should be prefered to global lookups where possible.
      $: function(selector) {
        return this.$el.find(selector);
      },
  
      // Initialize is an empty function by default. Override it with your own
      // initialization logic.
      initialize: function(){},
  
      // **render** is the core function that your view should override, in order
      // to populate its element (`this.el`), with the appropriate HTML. The
      // convention is for **render** to always return `this`.
      render: function() {
        return this;
      },
  
      // Remove this view by taking the element out of the DOM, and removing any
      // applicable Backbone.Events listeners.
      remove: function() {
        this.$el.remove();
        this.stopListening();
        return this;
      },
  
      // Change the view's element (`this.el` property), including event
      // re-delegation.
      setElement: function(element, delegate) {
        if (this.$el) this.undelegateEvents();
        this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
        this.el = this.$el[0];
        if (delegate !== false) this.delegateEvents();
        return this;
      },
  
      // Set callbacks, where `this.events` is a hash of
      //
      // *{"event selector": "callback"}*
      //
      //     {
      //       'mousedown .title':  'edit',
      //       'click .button':     'save'
      //       'click .open':       function(e) { ... }
      //     }
      //
      // pairs. Callbacks will be bound to the view, with `this` set properly.
      // Uses event delegation for efficiency.
      // Omitting the selector binds the event to `this.el`.
      // This only works for delegate-able events: not `focus`, `blur`, and
      // not `change`, `submit`, and `reset` in Internet Explorer.
      delegateEvents: function(events) {
        if (!(events || (events = _.result(this, 'events')))) return;
        this.undelegateEvents();
        for (var key in events) {
          var method = events[key];
          if (!_.isFunction(method)) method = this[events[key]];
          if (!method) throw new Error('Method "' + events[key] + '" does not exist');
          var match = key.match(delegateEventSplitter);
          var eventName = match[1], selector = match[2];
          method = _.bind(method, this);
          eventName += '.delegateEvents' + this.cid;
          if (selector === '') {
            this.$el.on(eventName, method);
          } else {
            this.$el.on(eventName, selector, method);
          }
        }
      },
  
      // Clears all callbacks previously bound to the view with `delegateEvents`.
      // You usually don't need to use this, but may wish to if you have multiple
      // Backbone views attached to the same DOM element.
      undelegateEvents: function() {
        this.$el.off('.delegateEvents' + this.cid);
      },
  
      // Performs the initial configuration of a View with a set of options.
      // Keys with special meaning *(model, collection, id, className)*, are
      // attached directly to the view.
      _configure: function(options) {
        if (this.options) options = _.extend({}, _.result(this, 'options'), options);
        _.extend(this, _.pick(options, viewOptions));
        this.options = options;
      },
  
      // Ensure that the View has a DOM element to render into.
      // If `this.el` is a string, pass it through `$()`, take the first
      // matching element, and re-assign it to `el`. Otherwise, create
      // an element from the `id`, `className` and `tagName` properties.
      _ensureElement: function() {
        if (!this.el) {
          var attrs = _.extend({}, _.result(this, 'attributes'));
          if (this.id) attrs.id = _.result(this, 'id');
          if (this.className) attrs['class'] = _.result(this, 'className');
          var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
          this.setElement($el, false);
        } else {
          this.setElement(_.result(this, 'el'), false);
        }
      }
  
    });
  
    // Backbone.sync
    // -------------
  
    // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
    var methodMap = {
      'create': 'POST',
      'update': 'PUT',
      'patch':  'PATCH',
      'delete': 'DELETE',
      'read':   'GET'
    };
  
    // Override this function to change the manner in which Backbone persists
    // models to the server. You will be passed the type of request, and the
    // model in question. By default, makes a RESTful Ajax request
    // to the model's `url()`. Some possible customizations could be:
    //
    // * Use `setTimeout` to batch rapid-fire updates into a single request.
    // * Send up the models as XML instead of JSON.
    // * Persist models via WebSockets instead of Ajax.
    //
    // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
    // as `POST`, with a `_method` parameter containing the true HTTP method,
    // as well as all requests with the body as `application/x-www-form-urlencoded`
    // instead of `application/json` with the model in a param named `model`.
    // Useful when interfacing with server-side languages like **PHP** that make
    // it difficult to read the body of `PUT` requests.
    Backbone.sync = function(method, model, options) {
      var type = methodMap[method];
  
      // Default options, unless specified.
      _.defaults(options || (options = {}), {
        emulateHTTP: Backbone.emulateHTTP,
        emulateJSON: Backbone.emulateJSON
      });
  
      // Default JSON-request options.
      var params = {type: type, dataType: 'json'};
  
      // Ensure that we have a URL.
      if (!options.url) {
        params.url = _.result(model, 'url') || urlError();
      }
  
      // Ensure that we have the appropriate request data.
      if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
        params.contentType = 'application/json';
        params.data = JSON.stringify(options.attrs || model.toJSON(options));
      }
  
      // For older servers, emulate JSON by encoding the request into an HTML-form.
      if (options.emulateJSON) {
        params.contentType = 'application/x-www-form-urlencoded';
        params.data = params.data ? {model: params.data} : {};
      }
  
      // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
      // And an `X-HTTP-Method-Override` header.
      if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
        params.type = 'POST';
        if (options.emulateJSON) params.data._method = type;
        var beforeSend = options.beforeSend;
        options.beforeSend = function(xhr) {
          xhr.setRequestHeader('X-HTTP-Method-Override', type);
          if (beforeSend) return beforeSend.apply(this, arguments);
        };
      }
  
      // Don't process data on a non-GET request.
      if (params.type !== 'GET' && !options.emulateJSON) {
        params.processData = false;
      }
  
      var success = options.success;
      options.success = function(resp) {
        if (success) success(model, resp, options);
        model.trigger('sync', model, resp, options);
      };
  
      var error = options.error;
      options.error = function(xhr) {
        if (error) error(model, xhr, options);
        model.trigger('error', model, xhr, options);
      };
  
      // Make the request, allowing the user to override any Ajax options.
      var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
      model.trigger('request', model, xhr, options);
      return xhr;
    };
  
    // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
    Backbone.ajax = function() {
      return Backbone.$.ajax.apply(Backbone.$, arguments);
    };
  
    // Helpers
    // -------
  
    // Helper function to correctly set up the prototype chain, for subclasses.
    // Similar to `goog.inherits`, but uses a hash of prototype properties and
    // class properties to be extended.
    var extend = function(protoProps, staticProps) {
      var parent = this;
      var child;
  
      // The constructor function for the new subclass is either defined by you
      // (the "constructor" property in your `extend` definition), or defaulted
      // by us to simply call the parent's constructor.
      if (protoProps && _.has(protoProps, 'constructor')) {
        child = protoProps.constructor;
      } else {
        child = function(){ return parent.apply(this, arguments); };
      }
  
      // Add static properties to the constructor function, if supplied.
      _.extend(child, parent, staticProps);
  
      // Set the prototype chain to inherit from `parent`, without calling
      // `parent`'s constructor function.
      var Surrogate = function(){ this.constructor = child; };
      Surrogate.prototype = parent.prototype;
      child.prototype = new Surrogate;
  
      // Add prototype properties (instance properties) to the subclass,
      // if supplied.
      if (protoProps) _.extend(child.prototype, protoProps);
  
      // Set a convenience property in case the parent's prototype is needed
      // later.
      child.__super__ = parent.prototype;
  
      return child;
    };
  
    // Set up inheritance for the model, collection, router, view and history.
    Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
  
    // Throw an error when a URL is needed, and none is supplied.
    var urlError = function() {
      throw new Error('A "url" property or function must be specified');
    };
  
  }).call(this);
  /*
      jQuery `input` special event v1.1
   
  <a class="linkclass" href="http://whattheheadsaid.com/projects/input-special-event">http://whattheheadsaid.com/projects/input-special-event</a>
   
      (c) 2010-2011 Andy Earnshaw
      MIT license
      <a class="linkclass" href="http://www.opensource.org/licenses/mit-license.php">www.opensource.org/licenses/mit-license.php</a>
  */
  (function($, udf) {
      var ns = ".inputEvent ",
          // A bunch of data strings that we use regularly
          dataBnd = "bound.inputEvent",
          dataVal = "value.inputEvent",
          dataDlg = "delegated.inputEvent",
          txtinput = "txtinput",
          // Set up our list of events
          bindTo = [
              "input", "textInput", "propertychange", "paste", "cut", "keydown", "drop",
          ""].join(ns),
          // Events required for delegate, mostly for IE support
          dlgtTo = [ "focusin", "mouseover", "dragstart", "" ].join(ns),
          // Elements supporting text input, not including contentEditable
          supported = {TEXTAREA:udf, INPUT:udf},
          // Events that fire before input value is updated
          delay = { paste:udf, cut:udf, keydown:udf, drop:udf, textInput:udf };
  
      $.event.special.txtinput = {
          setup: function(data, namespaces, handler) {
              var timer,
                  bndCount,
                  // Get references to the element
                  elem  = this,
                  $elem = $(this),
                  triggered = false;
   
              if (elem.tagName in supported) {
                  bndCount = $.data(elem, dataBnd) || 0;
   
                  if (!bndCount)
                      $elem.bind(bindTo, handler);
   
                  $.data(elem, dataBnd, ++bndCount);
                  $.data(elem, dataVal, elem.value);
              } else {
                  $elem.bind(dlgtTo, function (e) {
                      var target = e.target;
                      if (target.tagName in supported && !$.data(elem, dataDlg)) {
                          bndCount = $.data(target, dataBnd) || 0;
   
                          if (!bndCount)
                              target.bind(bindTo, handler);
   
                          // make sure we increase the count only once for each bound ancestor
                          $.data(elem, dataDlg, true);
                          $.data(target, dataBnd, ++bndCount);
                          $.data(target, dataVal, target.value);
                      }
                  });
              }
              function handler (e) {
                  var elem = e.target;
   
                  // Clear previous timers because we only need to know about 1 change
                  window.clearTimeout(timer), timer = null;
   
                  // Return if we've already triggered the event
                  if (triggered)
                      return;
   
                  // paste, cut, keydown and drop all fire before the value is updated
                  if (e.type in delay && !timer) {
                      // ...so we need to delay them until after the event has fired
                      timer = window.setTimeout(function () {
                          if (elem.value !== $.data(elem, dataVal)) {
                              $(elem).trigger(txtinput);
                              $.data(elem, dataVal, elem.value);
                          }
                      }, 0);
                  }
                  else if (e.type == "propertychange") {
                      if (e.originalEvent.propertyName == "value") {
                          $(elem).trigger(txtinput);
                          $.data(elem, dataVal, elem.value);
                          triggered = true;
                          window.setTimeout(function () {
                              triggered = false;
                          }, 0);
                      }
                  }
                  else {
                      $(elem).trigger(txtinput);
                      $.data(elem, dataVal, elem.value);
                      triggered = true;
                      window.setTimeout(function () {
                          triggered = false;
                      }, 0);
                  }
              }
          },
          teardown: function () {
              var elem = $(this);
              elem.unbind(dlgtTo);
              elem.find("input, textarea").andSelf().each(function () {
                  bndCount = $.data(this, dataBnd, ($.data(this, dataBnd) || 1)-1);
   
                  if (!bndCount)
                      elem.unbind(bindTo);
              });
          }
      };
   
      // Setup our jQuery shorthand method
      $.fn.input = function (handler) {
          return handler ? this.bind(txtinput, handler) : this.trigger(txtinput);
      }
  })(jQuery);
  /*jshint eqnull:true */
  /*!
   * jQuery Cookie Plugin v1.1
   * https://github.com/carhartl/jquery-cookie
   *
   * Copyright 2011, Klaus Hartl
   * Dual licensed under the MIT or GPL Version 2 licenses.
   * http://www.opensource.org/licenses/mit-license.php
   * http://www.opensource.org/licenses/GPL-2.0
   */
  (function($, document) {
  
  	var pluses = /\+/g;
  	function raw(s) {
  		return s;
  	}
  	function decoded(s) {
  		return decodeURIComponent(s.replace(pluses, ' '));
  	}
  
  	$.cookie = function(key, value, options) {
  
  		// key and at least value given, set cookie...
  		if (arguments.length > 1 && (!/Object/.test(Object.prototype.toString.call(value)) || value == null)) {
  			options = $.extend({}, $.cookie.defaults, options);
  
  			if (value == null) {
  				options.expires = -1;
  			}
  
  			if (typeof options.expires === 'number') {
  				var days = options.expires, t = options.expires = new Date();
  				t.setDate(t.getDate() + days);
  			}
  
  			value = String(value);
  
  			return (document.cookie = [
  				encodeURIComponent(key), '=', options.raw ? value : encodeURIComponent(value),
  				options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
  				options.path    ? '; path=' + options.path : '',
  				options.domain  ? '; domain=' + options.domain : '',
  				options.secure  ? '; secure' : ''
  			].join(''));
  		}
  
  		// key and possibly options given, get cookie...
  		options = value || $.cookie.defaults || {};
  		var decode = options.raw ? raw : decoded;
  		var cookies = document.cookie.split('; ');
  		for (var i = 0, parts; (parts = cookies[i] && cookies[i].split('=')); i++) {
  			if (decode(parts.shift()) === key) {
  				return decode(parts.join('='));
  			}
  		}
  		return null;
  	};
  
  	$.cookie.defaults = {};
  
  })(jQuery, document);
  