Category: 主干

  • WordPress 源代码——主干(underscore-1.4.4.js)

    WordPress 源代码——主干(underscore-1.4.4.js)

    1	//     Underscore.js 1.4.4
    2	//     http://underscorejs.org
    3	//     (c) 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
    4	//     Underscore may be freely distributed under the MIT license.
    5	
    6	(function() {
    7	
    8	  // Baseline setup
    9	  // --------------
    10	
    11	  // Establish the root object, `window` in the browser, or `global` on the server.
    12	  var root = this;
    13	
    14	  // Save the previous value of the `_` variable.
    15	  var previousUnderscore = root._;
    16	
    17	  // Establish the object that gets returned to break out of a loop iteration.
    18	  var breaker = {};
    19	
    20	  // Save bytes in the minified (but not gzipped) version:
    21	  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
    22	
    23	  // Create quick reference variables for speed access to core prototypes.
    24	  var push             = ArrayProto.push,
    25	      slice            = ArrayProto.slice,
    26	      concat           = ArrayProto.concat,
    27	      toString         = ObjProto.toString,
    28	      hasOwnProperty   = ObjProto.hasOwnProperty;
    29	
    30	  // All **ECMAScript 5** native function implementations that we hope to use
    31	  // are declared here.
    32	  var
    33	    nativeForEach      = ArrayProto.forEach,
    34	    nativeMap          = ArrayProto.map,
    35	    nativeReduce       = ArrayProto.reduce,
    36	    nativeReduceRight  = ArrayProto.reduceRight,
    37	    nativeFilter       = ArrayProto.filter,
    38	    nativeEvery        = ArrayProto.every,
    39	    nativeSome         = ArrayProto.some,
    40	    nativeIndexOf      = ArrayProto.indexOf,
    41	    nativeLastIndexOf  = ArrayProto.lastIndexOf,
    42	    nativeIsArray      = Array.isArray,
    43	    nativeKeys         = Object.keys,
    44	    nativeBind         = FuncProto.bind;
    45	
    46	  // Create a safe reference to the Underscore object for use below.
    47	  var _ = function(obj) {
    48	    if (obj instanceof _) return obj;
    49	    if (!(this instanceof _)) return new _(obj);
    50	    this._wrapped = obj;
    51	  };
    52	
    53	  // Export the Underscore object for **Node.js**, with
    54	  // backwards-compatibility for the old `require()` API. If we're in
    55	  // the browser, add `_` as a global object via a string identifier,
    56	  // for Closure Compiler "advanced" mode.
    57	  if (typeof exports !== 'undefined') {
    58	    if (typeof module !== 'undefined' && module.exports) {
    59	      exports = module.exports = _;
    60	    }
    61	    exports._ = _;
    62	  } else {
    63	    root._ = _;
    64	  }
    65	
    66	  // Current version.
    67	  _.VERSION = '1.4.4';
    68	
    69	  // Collection Functions
    70	  // --------------------
    71	
    72	  // The cornerstone, an `each` implementation, aka `forEach`.
    73	  // Handles objects with the built-in `forEach`, arrays, and raw objects.
    74	  // Delegates to **ECMAScript 5**'s native `forEach` if available.
    75	  var each = _.each = _.forEach = function(obj, iterator, context) {
    76	    if (obj == null) return;
    77	    if (nativeForEach && obj.forEach === nativeForEach) {
    78	      obj.forEach(iterator, context);
    79	    } else if (obj.length === +obj.length) {
    80	      for (var i = 0, l = obj.length; i < l; i++) {
    81	        if (iterator.call(context, obj[i], i, obj) === breaker) return;
    82	      }
    83	    } else {
    84	      for (var key in obj) {
    85	        if (_.has(obj, key)) {
    86	          if (iterator.call(context, obj[key], key, obj) === breaker) return;
    87	        }
    88	      }
    89	    }
    90	  };
    91	
    92	  // Return the results of applying the iterator to each element.
    93	  // Delegates to **ECMAScript 5**'s native `map` if available.
    94	  _.map = _.collect = function(obj, iterator, context) {
    95	    var results = [];
    96	    if (obj == null) return results;
    97	    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    98	    each(obj, function(value, index, list) {
    99	      results[results.length] = iterator.call(context, value, index, list);
    100	    });
    101	    return results;
    102	  };
    103	
    104	  var reduceError = 'Reduce of empty array with no initial value';
    105	
    106	  // **Reduce** builds up a single result from a list of values, aka `inject`,
    107	  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
    108	  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    109	    var initial = arguments.length > 2;
    110	    if (obj == null) obj = [];
    111	    if (nativeReduce && obj.reduce === nativeReduce) {
    112	      if (context) iterator = _.bind(iterator, context);
    113	      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    114	    }
    115	    each(obj, function(value, index, list) {
    116	      if (!initial) {
    117	        memo = value;
    118	        initial = true;
    119	      } else {
    120	        memo = iterator.call(context, memo, value, index, list);
    121	      }
    122	    });
    123	    if (!initial) throw new TypeError(reduceError);
    124	    return memo;
    125	  };
    126	
    127	  // The right-associative version of reduce, also known as `foldr`.
    128	  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
    129	  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    130	    var initial = arguments.length > 2;
    131	    if (obj == null) obj = [];
    132	    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
    133	      if (context) iterator = _.bind(iterator, context);
    134	      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    135	    }
    136	    var length = obj.length;
    137	    if (length !== +length) {
    138	      var keys = _.keys(obj);
    139	      length = keys.length;
    140	    }
    141	    each(obj, function(value, index, list) {
    142	      index = keys ? keys[--length] : --length;
    143	      if (!initial) {
    144	        memo = obj[index];
    145	        initial = true;
    146	      } else {
    147	        memo = iterator.call(context, memo, obj[index], index, list);
    148	      }
    149	    });
    150	    if (!initial) throw new TypeError(reduceError);
    151	    return memo;
    152	  };
    153	
    154	  // Return the first value which passes a truth test. Aliased as `detect`.
    155	  _.find = _.detect = function(obj, iterator, context) {
    156	    var result;
    157	    any(obj, function(value, index, list) {
    158	      if (iterator.call(context, value, index, list)) {
    159	        result = value;
    160	        return true;
    161	      }
    162	    });
    163	    return result;
    164	  };
    165	
    166	  // Return all the elements that pass a truth test.
    167	  // Delegates to **ECMAScript 5**'s native `filter` if available.
    168	  // Aliased as `select`.
    169	  _.filter = _.select = function(obj, iterator, context) {
    170	    var results = [];
    171	    if (obj == null) return results;
    172	    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
    173	    each(obj, function(value, index, list) {
    174	      if (iterator.call(context, value, index, list)) results[results.length] = value;
    175	    });
    176	    return results;
    177	  };
    178	
    179	  // Return all the elements for which a truth test fails.
    180	  _.reject = function(obj, iterator, context) {
    181	    return _.filter(obj, function(value, index, list) {
    182	      return !iterator.call(context, value, index, list);
    183	    }, context);
    184	  };
    185	
    186	  // Determine whether all of the elements match a truth test.
    187	  // Delegates to **ECMAScript 5**'s native `every` if available.
    188	  // Aliased as `all`.
    189	  _.every = _.all = function(obj, iterator, context) {
    190	    iterator || (iterator = _.identity);
    191	    var result = true;
    192	    if (obj == null) return result;
    193	    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
    194	    each(obj, function(value, index, list) {
    195	      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
    196	    });
    197	    return !!result;
    198	  };
    199	
    200	  // Determine if at least one element in the object matches a truth test.
    201	  // Delegates to **ECMAScript 5**'s native `some` if available.
    202	  // Aliased as `any`.
    203	  var any = _.some = _.any = function(obj, iterator, context) {
    204	    iterator || (iterator = _.identity);
    205	    var result = false;
    206	    if (obj == null) return result;
    207	    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
    208	    each(obj, function(value, index, list) {
    209	      if (result || (result = iterator.call(context, value, index, list))) return breaker;
    210	    });
    211	    return !!result;
    212	  };
    213	
    214	  // Determine if the array or object contains a given value (using `===`).
    215	  // Aliased as `include`.
    216	  _.contains = _.include = function(obj, target) {
    217	    if (obj == null) return false;
    218	    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
    219	    return any(obj, function(value) {
    220	      return value === target;
    221	    });
    222	  };
    223	
    224	  // Invoke a method (with arguments) on every item in a collection.
    225	  _.invoke = function(obj, method) {
    226	    var args = slice.call(arguments, 2);
    227	    var isFunc = _.isFunction(method);
    228	    return _.map(obj, function(value) {
    229	      return (isFunc ? method : value[method]).apply(value, args);
    230	    });
    231	  };
    232	
    233	  // Convenience version of a common use case of `map`: fetching a property.
    234	  _.pluck = function(obj, key) {
    235	    return _.map(obj, function(value){ return value[key]; });
    236	  };
    237	
    238	  // Convenience version of a common use case of `filter`: selecting only objects
    239	  // containing specific `key:value` pairs.
    240	  _.where = function(obj, attrs, first) {
    241	    if (_.isEmpty(attrs)) return first ? null : [];
    242	    return _[first ? 'find' : 'filter'](obj, function(value) {
    243	      for (var key in attrs) {
    244	        if (attrs[key] !== value[key]) return false;
    245	      }
    246	      return true;
    247	    });
    248	  };
    249	
    250	  // Convenience version of a common use case of `find`: getting the first object
    251	  // containing specific `key:value` pairs.
    252	  _.findWhere = function(obj, attrs) {
    253	    return _.where(obj, attrs, true);
    254	  };
    255	
    256	  // Return the maximum element or (element-based computation).
    257	  // Can't optimize arrays of integers longer than 65,535 elements.
    258	  // See: https://bugs.webkit.org/show_bug.cgi?id=80797
    259	  _.max = function(obj, iterator, context) {
    260	    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    261	      return Math.max.apply(Math, obj);
    262	    }
    263	    if (!iterator && _.isEmpty(obj)) return -Infinity;
    264	    var result = {computed : -Infinity, value: -Infinity};
    265	    each(obj, function(value, index, list) {
    266	      var computed = iterator ? iterator.call(context, value, index, list) : value;
    267	      computed >= result.computed && (result = {value : value, computed : computed});
    268	    });
    269	    return result.value;
    270	  };
    271	
    272	  // Return the minimum element (or element-based computation).
    273	  _.min = function(obj, iterator, context) {
    274	    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    275	      return Math.min.apply(Math, obj);
    276	    }
    277	    if (!iterator && _.isEmpty(obj)) return Infinity;
    278	    var result = {computed : Infinity, value: Infinity};
    279	    each(obj, function(value, index, list) {
    280	      var computed = iterator ? iterator.call(context, value, index, list) : value;
    281	      computed < result.computed && (result = {value : value, computed : computed});
    282	    });
    283	    return result.value;
    284	  };
    285	
    286	  // Shuffle an array.
    287	  _.shuffle = function(obj) {
    288	    var rand;
    289	    var index = 0;
    290	    var shuffled = [];
    291	    each(obj, function(value) {
    292	      rand = _.random(index++);
    293	      shuffled[index - 1] = shuffled[rand];
    294	      shuffled[rand] = value;
    295	    });
    296	    return shuffled;
    297	  };
    298	
    299	  // An internal function to generate lookup iterators.
    300	  var lookupIterator = function(value) {
    301	    return _.isFunction(value) ? value : function(obj){ return obj[value]; };
    302	  };
    303	
    304	  // Sort the object's values by a criterion produced by an iterator.
    305	  _.sortBy = function(obj, value, context) {
    306	    var iterator = lookupIterator(value);
    307	    return _.pluck(_.map(obj, function(value, index, list) {
    308	      return {
    309	        value : value,
    310	        index : index,
    311	        criteria : iterator.call(context, value, index, list)
    312	      };
    313	    }).sort(function(left, right) {
    314	      var a = left.criteria;
    315	      var b = right.criteria;
    316	      if (a !== b) {
    317	        if (a > b || a === void 0) return 1;
    318	        if (a < b || b === void 0) return -1;
    319	      }
    320	      return left.index < right.index ? -1 : 1;
    321	    }), 'value');
    322	  };
    323	
    324	  // An internal function used for aggregate "group by" operations.
    325	  var group = function(obj, value, context, behavior) {
    326	    var result = {};
    327	    var iterator = lookupIterator(value || _.identity);
    328	    each(obj, function(value, index) {
    329	      var key = iterator.call(context, value, index, obj);
    330	      behavior(result, key, value);
    331	    });
    332	    return result;
    333	  };
    334	
    335	  // Groups the object's values by a criterion. Pass either a string attribute
    336	  // to group by, or a function that returns the criterion.
    337	  _.groupBy = function(obj, value, context) {
    338	    return group(obj, value, context, function(result, key, value) {
    339	      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
    340	    });
    341	  };
    342	
    343	  // Counts instances of an object that group by a certain criterion. Pass
    344	  // either a string attribute to count by, or a function that returns the
    345	  // criterion.
    346	  _.countBy = function(obj, value, context) {
    347	    return group(obj, value, context, function(result, key) {
    348	      if (!_.has(result, key)) result[key] = 0;
    349	      result[key]++;
    350	    });
    351	  };
    352	
    353	  // Use a comparator function to figure out the smallest index at which
    354	  // an object should be inserted so as to maintain order. Uses binary search.
    355	  _.sortedIndex = function(array, obj, iterator, context) {
    356	    iterator = iterator == null ? _.identity : lookupIterator(iterator);
    357	    var value = iterator.call(context, obj);
    358	    var low = 0, high = array.length;
    359	    while (low < high) {
    360	      var mid = (low + high) >>> 1;
    361	      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
    362	    }
    363	    return low;
    364	  };
    365	
    366	  // Safely convert anything iterable into a real, live array.
    367	  _.toArray = function(obj) {
    368	    if (!obj) return [];
    369	    if (_.isArray(obj)) return slice.call(obj);
    370	    if (obj.length === +obj.length) return _.map(obj, _.identity);
    371	    return _.values(obj);
    372	  };
    373	
    374	  // Return the number of elements in an object.
    375	  _.size = function(obj) {
    376	    if (obj == null) return 0;
    377	    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
    378	  };
    379	
    380	  // Array Functions
    381	  // ---------------
    382	
    383	  // Get the first element of an array. Passing **n** will return the first N
    384	  // values in the array. Aliased as `head` and `take`. The **guard** check
    385	  // allows it to work with `_.map`.
    386	  _.first = _.head = _.take = function(array, n, guard) {
    387	    if (array == null) return void 0;
    388	    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
    389	  };
    390	
    391	  // Returns everything but the last entry of the array. Especially useful on
    392	  // the arguments object. Passing **n** will return all the values in
    393	  // the array, excluding the last N. The **guard** check allows it to work with
    394	  // `_.map`.
    395	  _.initial = function(array, n, guard) {
    396	    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
    397	  };
    398	
    399	  // Get the last element of an array. Passing **n** will return the last N
    400	  // values in the array. The **guard** check allows it to work with `_.map`.
    401	  _.last = function(array, n, guard) {
    402	    if (array == null) return void 0;
    403	    if ((n != null) && !guard) {
    404	      return slice.call(array, Math.max(array.length - n, 0));
    405	    } else {
    406	      return array[array.length - 1];
    407	    }
    408	  };
    409	
    410	  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    411	  // Especially useful on the arguments object. Passing an **n** will return
    412	  // the rest N values in the array. The **guard**
    413	  // check allows it to work with `_.map`.
    414	  _.rest = _.tail = _.drop = function(array, n, guard) {
    415	    return slice.call(array, (n == null) || guard ? 1 : n);
    416	  };
    417	
    418	  // Trim out all falsy values from an array.
    419	  _.compact = function(array) {
    420	    return _.filter(array, _.identity);
    421	  };
    422	
    423	  // Internal implementation of a recursive `flatten` function.
    424	  var flatten = function(input, shallow, output) {
    425	    each(input, function(value) {
    426	      if (_.isArray(value)) {
    427	        shallow ? push.apply(output, value) : flatten(value, shallow, output);
    428	      } else {
    429	        output.push(value);
    430	      }
    431	    });
    432	    return output;
    433	  };
    434	
    435	  // Return a completely flattened version of an array.
    436	  _.flatten = function(array, shallow) {
    437	    return flatten(array, shallow, []);
    438	  };
    439	
    440	  // Return a version of the array that does not contain the specified value(s).
    441	  _.without = function(array) {
    442	    return _.difference(array, slice.call(arguments, 1));
    443	  };
    444	
    445	  // Produce a duplicate-free version of the array. If the array has already
    446	  // been sorted, you have the option of using a faster algorithm.
    447	  // Aliased as `unique`.
    448	  _.uniq = _.unique = function(array, isSorted, iterator, context) {
    449	    if (_.isFunction(isSorted)) {
    450	      context = iterator;
    451	      iterator = isSorted;
    452	      isSorted = false;
    453	    }
    454	    var initial = iterator ? _.map(array, iterator, context) : array;
    455	    var results = [];
    456	    var seen = [];
    457	    each(initial, function(value, index) {
    458	      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
    459	        seen.push(value);
    460	        results.push(array[index]);
    461	      }
    462	    });
    463	    return results;
    464	  };
    465	
    466	  // Produce an array that contains the union: each distinct element from all of
    467	  // the passed-in arrays.
    468	  _.union = function() {
    469	    return _.uniq(concat.apply(ArrayProto, arguments));
    470	  };
    471	
    472	  // Produce an array that contains every item shared between all the
    473	  // passed-in arrays.
    474	  _.intersection = function(array) {
    475	    var rest = slice.call(arguments, 1);
    476	    return _.filter(_.uniq(array), function(item) {
    477	      return _.every(rest, function(other) {
    478	        return _.indexOf(other, item) >= 0;
    479	      });
    480	    });
    481	  };
    482	
    483	  // Take the difference between one array and a number of other arrays.
    484	  // Only the elements present in just the first array will remain.
    485	  _.difference = function(array) {
    486	    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
    487	    return _.filter(array, function(value){ return !_.contains(rest, value); });
    488	  };
    489	
    490	  // Zip together multiple lists into a single array -- elements that share
    491	  // an index go together.
    492	  _.zip = function() {
    493	    var args = slice.call(arguments);
    494	    var length = _.max(_.pluck(args, 'length'));
    495	    var results = new Array(length);
    496	    for (var i = 0; i < length; i++) {
    497	      results[i] = _.pluck(args, "" + i);
    498	    }
    499	    return results;
    500	  };
    501	
    502	  // Converts lists into objects. Pass either a single array of `[key, value]`
    503	  // pairs, or two parallel arrays of the same length -- one of keys, and one of
    504	  // the corresponding values.
    505	  _.object = function(list, values) {
    506	    if (list == null) return {};
    507	    var result = {};
    508	    for (var i = 0, l = list.length; i < l; i++) {
    509	      if (values) {
    510	        result[list[i]] = values[i];
    511	      } else {
    512	        result[list[i][0]] = list[i][1];
    513	      }
    514	    }
    515	    return result;
    516	  };
    517	
    518	  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
    519	  // we need this function. Return the position of the first occurrence of an
    520	  // item in an array, or -1 if the item is not included in the array.
    521	  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
    522	  // If the array is large and already in sort order, pass `true`
    523	  // for **isSorted** to use binary search.
    524	  _.indexOf = function(array, item, isSorted) {
    525	    if (array == null) return -1;
    526	    var i = 0, l = array.length;
    527	    if (isSorted) {
    528	      if (typeof isSorted == 'number') {
    529	        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
    530	      } else {
    531	        i = _.sortedIndex(array, item);
    532	        return array[i] === item ? i : -1;
    533	      }
    534	    }
    535	    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    536	    for (; i < l; i++) if (array[i] === item) return i;
    537	    return -1;
    538	  };
    539	
    540	  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
    541	  _.lastIndexOf = function(array, item, from) {
    542	    if (array == null) return -1;
    543	    var hasIndex = from != null;
    544	    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
    545	      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
    546	    }
    547	    var i = (hasIndex ? from : array.length);
    548	    while (i--) if (array[i] === item) return i;
    549	    return -1;
    550	  };
    551	
    552	  // Generate an integer Array containing an arithmetic progression. A port of
    553	  // the native Python `range()` function. See
    554	  // [the Python documentation](http://docs.python.org/library/functions.html#range).
    555	  _.range = function(start, stop, step) {
    556	    if (arguments.length <= 1) {
    557	      stop = start || 0;
    558	      start = 0;
    559	    }
    560	    step = arguments[2] || 1;
    561	
    562	    var len = Math.max(Math.ceil((stop - start) / step), 0);
    563	    var idx = 0;
    564	    var range = new Array(len);
    565	
    566	    while(idx < len) {
    567	      range[idx++] = start;
    568	      start += step;
    569	    }
    570	
    571	    return range;
    572	  };
    573	
    574	  // Function (ahem) Functions
    575	  // ------------------
    576	
    577	  // Create a function bound to a given object (assigning `this`, and arguments,
    578	  // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
    579	  // available.
    580	  _.bind = function(func, context) {
    581	    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
    582	    var args = slice.call(arguments, 2);
    583	    return function() {
    584	      return func.apply(context, args.concat(slice.call(arguments)));
    585	    };
    586	  };
    587	
    588	  // Partially apply a function by creating a version that has had some of its
    589	  // arguments pre-filled, without changing its dynamic `this` context.
    590	  _.partial = function(func) {
    591	    var args = slice.call(arguments, 1);
    592	    return function() {
    593	      return func.apply(this, args.concat(slice.call(arguments)));
    594	    };
    595	  };
    596	
    597	  // Bind all of an object's methods to that object. Useful for ensuring that
    598	  // all callbacks defined on an object belong to it.
    599	  _.bindAll = function(obj) {
    600	    var funcs = slice.call(arguments, 1);
    601	    if (funcs.length === 0) funcs = _.functions(obj);
    602	    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
    603	    return obj;
    604	  };
    605	
    606	  // Memoize an expensive function by storing its results.
    607	  _.memoize = function(func, hasher) {
    608	    var memo = {};
    609	    hasher || (hasher = _.identity);
    610	    return function() {
    611	      var key = hasher.apply(this, arguments);
    612	      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
    613	    };
    614	  };
    615	
    616	  // Delays a function for the given number of milliseconds, and then calls
    617	  // it with the arguments supplied.
    618	  _.delay = function(func, wait) {
    619	    var args = slice.call(arguments, 2);
    620	    return setTimeout(function(){ return func.apply(null, args); }, wait);
    621	  };
    622	
    623	  // Defers a function, scheduling it to run after the current call stack has
    624	  // cleared.
    625	  _.defer = function(func) {
    626	    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
    627	  };
    628	
    629	  // Returns a function, that, when invoked, will only be triggered at most once
    630	  // during a given window of time.
    631	  _.throttle = function(func, wait) {
    632	    var context, args, timeout, result;
    633	    var previous = 0;
    634	    var later = function() {
    635	      previous = new Date;
    636	      timeout = null;
    637	      result = func.apply(context, args);
    638	    };
    639	    return function() {
    640	      var now = new Date;
    641	      var remaining = wait - (now - previous);
    642	      context = this;
    643	      args = arguments;
    644	      if (remaining <= 0) {
    645	        clearTimeout(timeout);
    646	        timeout = null;
    647	        previous = now;
    648	        result = func.apply(context, args);
    649	      } else if (!timeout) {
    650	        timeout = setTimeout(later, remaining);
    651	      }
    652	      return result;
    653	    };
    654	  };
    655	
    656	  // Returns a function, that, as long as it continues to be invoked, will not
    657	  // be triggered. The function will be called after it stops being called for
    658	  // N milliseconds. If `immediate` is passed, trigger the function on the
    659	  // leading edge, instead of the trailing.
    660	  _.debounce = function(func, wait, immediate) {
    661	    var timeout, result;
    662	    return function() {
    663	      var context = this, args = arguments;
    664	      var later = function() {
    665	        timeout = null;
    666	        if (!immediate) result = func.apply(context, args);
    667	      };
    668	      var callNow = immediate && !timeout;
    669	      clearTimeout(timeout);
    670	      timeout = setTimeout(later, wait);
    671	      if (callNow) result = func.apply(context, args);
    672	      return result;
    673	    };
    674	  };
    675	
    676	  // Returns a function that will be executed at most one time, no matter how
    677	  // often you call it. Useful for lazy initialization.
    678	  _.once = function(func) {
    679	    var ran = false, memo;
    680	    return function() {
    681	      if (ran) return memo;
    682	      ran = true;
    683	      memo = func.apply(this, arguments);
    684	      func = null;
    685	      return memo;
    686	    };
    687	  };
    688	
    689	  // Returns the first function passed as an argument to the second,
    690	  // allowing you to adjust arguments, run code before and after, and
    691	  // conditionally execute the original function.
    692	  _.wrap = function(func, wrapper) {
    693	    return function() {
    694	      var args = [func];
    695	      push.apply(args, arguments);
    696	      return wrapper.apply(this, args);
    697	    };
    698	  };
    699	
    700	  // Returns a function that is the composition of a list of functions, each
    701	  // consuming the return value of the function that follows.
    702	  _.compose = function() {
    703	    var funcs = arguments;
    704	    return function() {
    705	      var args = arguments;
    706	      for (var i = funcs.length - 1; i >= 0; i--) {
    707	        args = [funcs[i].apply(this, args)];
    708	      }
    709	      return args[0];
    710	    };
    711	  };
    712	
    713	  // Returns a function that will only be executed after being called N times.
    714	  _.after = function(times, func) {
    715	    if (times <= 0) return func();
    716	    return function() {
    717	      if (--times < 1) {
    718	        return func.apply(this, arguments);
    719	      }
    720	    };
    721	  };
    722	
    723	  // Object Functions
    724	  // ----------------
    725	
    726	  // Retrieve the names of an object's properties.
    727	  // Delegates to **ECMAScript 5**'s native `Object.keys`
    728	  _.keys = nativeKeys || function(obj) {
    729	    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    730	    var keys = [];
    731	    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
    732	    return keys;
    733	  };
    734	
    735	  // Retrieve the values of an object's properties.
    736	  _.values = function(obj) {
    737	    var values = [];
    738	    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
    739	    return values;
    740	  };
    741	
    742	  // Convert an object into a list of `[key, value]` pairs.
    743	  _.pairs = function(obj) {
    744	    var pairs = [];
    745	    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
    746	    return pairs;
    747	  };
    748	
    749	  // Invert the keys and values of an object. The values must be serializable.
    750	  _.invert = function(obj) {
    751	    var result = {};
    752	    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
    753	    return result;
    754	  };
    755	
    756	  // Return a sorted list of the function names available on the object.
    757	  // Aliased as `methods`
    758	  _.functions = _.methods = function(obj) {
    759	    var names = [];
    760	    for (var key in obj) {
    761	      if (_.isFunction(obj[key])) names.push(key);
    762	    }
    763	    return names.sort();
    764	  };
    765	
    766	  // Extend a given object with all the properties in passed-in object(s).
    767	  _.extend = function(obj) {
    768	    each(slice.call(arguments, 1), function(source) {
    769	      if (source) {
    770	        for (var prop in source) {
    771	          obj[prop] = source[prop];
    772	        }
    773	      }
    774	    });
    775	    return obj;
    776	  };
    777	
    778	  // Return a copy of the object only containing the whitelisted properties.
    779	  _.pick = function(obj) {
    780	    var copy = {};
    781	    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    782	    each(keys, function(key) {
    783	      if (key in obj) copy[key] = obj[key];
    784	    });
    785	    return copy;
    786	  };
    787	
    788	   // Return a copy of the object without the blacklisted properties.
    789	  _.omit = function(obj) {
    790	    var copy = {};
    791	    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    792	    for (var key in obj) {
    793	      if (!_.contains(keys, key)) copy[key] = obj[key];
    794	    }
    795	    return copy;
    796	  };
    797	
    798	  // Fill in a given object with default properties.
    799	  _.defaults = function(obj) {
    800	    each(slice.call(arguments, 1), function(source) {
    801	      if (source) {
    802	        for (var prop in source) {
    803	          if (obj[prop] == null) obj[prop] = source[prop];
    804	        }
    805	      }
    806	    });
    807	    return obj;
    808	  };
    809	
    810	  // Create a (shallow-cloned) duplicate of an object.
    811	  _.clone = function(obj) {
    812	    if (!_.isObject(obj)) return obj;
    813	    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    814	  };
    815	
    816	  // Invokes interceptor with the obj, and then returns obj.
    817	  // The primary purpose of this method is to "tap into" a method chain, in
    818	  // order to perform operations on intermediate results within the chain.
    819	  _.tap = function(obj, interceptor) {
    820	    interceptor(obj);
    821	    return obj;
    822	  };
    823	
    824	  // Internal recursive comparison function for `isEqual`.
    825	  var eq = function(a, b, aStack, bStack) {
    826	    // Identical objects are equal. `0 === -0`, but they aren't identical.
    827	    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
    828	    if (a === b) return a !== 0 || 1 / a == 1 / b;
    829	    // A strict comparison is necessary because `null == undefined`.
    830	    if (a == null || b == null) return a === b;
    831	    // Unwrap any wrapped objects.
    832	    if (a instanceof _) a = a._wrapped;
    833	    if (b instanceof _) b = b._wrapped;
    834	    // Compare `[[Class]]` names.
    835	    var className = toString.call(a);
    836	    if (className != toString.call(b)) return false;
    837	    switch (className) {
    838	      // Strings, numbers, dates, and booleans are compared by value.
    839	      case '[object String]':
    840	        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
    841	        // equivalent to `new String("5")`.
    842	        return a == String(b);
    843	      case '[object Number]':
    844	        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
    845	        // other numeric values.
    846	        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
    847	      case '[object Date]':
    848	      case '[object Boolean]':
    849	        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
    850	        // millisecond representations. Note that invalid dates with millisecond representations
    851	        // of `NaN` are not equivalent.
    852	        return +a == +b;
    853	      // RegExps are compared by their source patterns and flags.
    854	      case '[object RegExp]':
    855	        return a.source == b.source &&
    856	               a.global == b.global &&
    857	               a.multiline == b.multiline &&
    858	               a.ignoreCase == b.ignoreCase;
    859	    }
    860	    if (typeof a != 'object' || typeof b != 'object') return false;
    861	    // Assume equality for cyclic structures. The algorithm for detecting cyclic
    862	    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
    863	    var length = aStack.length;
    864	    while (length--) {
    865	      // Linear search. Performance is inversely proportional to the number of
    866	      // unique nested structures.
    867	      if (aStack[length] == a) return bStack[length] == b;
    868	    }
    869	    // Add the first object to the stack of traversed objects.
    870	    aStack.push(a);
    871	    bStack.push(b);
    872	    var size = 0, result = true;
    873	    // Recursively compare objects and arrays.
    874	    if (className == '[object Array]') {
    875	      // Compare array lengths to determine if a deep comparison is necessary.
    876	      size = a.length;
    877	      result = size == b.length;
    878	      if (result) {
    879	        // Deep compare the contents, ignoring non-numeric properties.
    880	        while (size--) {
    881	          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
    882	        }
    883	      }
    884	    } else {
    885	      // Objects with different constructors are not equivalent, but `Object`s
    886	      // from different frames are.
    887	      var aCtor = a.constructor, bCtor = b.constructor;
    888	      if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
    889	                               _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
    890	        return false;
    891	      }
    892	      // Deep compare objects.
    893	      for (var key in a) {
    894	        if (_.has(a, key)) {
    895	          // Count the expected number of properties.
    896	          size++;
    897	          // Deep compare each member.
    898	          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
    899	        }
    900	      }
    901	      // Ensure that both objects contain the same number of properties.
    902	      if (result) {
    903	        for (key in b) {
    904	          if (_.has(b, key) && !(size--)) break;
    905	        }
    906	        result = !size;
    907	      }
    908	    }
    909	    // Remove the first object from the stack of traversed objects.
    910	    aStack.pop();
    911	    bStack.pop();
    912	    return result;
    913	  };
    914	
    915	  // Perform a deep comparison to check if two objects are equal.
    916	  _.isEqual = function(a, b) {
    917	    return eq(a, b, [], []);
    918	  };
    919	
    920	  // Is a given array, string, or object empty?
    921	  // An "empty" object has no enumerable own-properties.
    922	  _.isEmpty = function(obj) {
    923	    if (obj == null) return true;
    924	    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
    925	    for (var key in obj) if (_.has(obj, key)) return false;
    926	    return true;
    927	  };
    928	
    929	  // Is a given value a DOM element?
    930	  _.isElement = function(obj) {
    931	    return !!(obj && obj.nodeType === 1);
    932	  };
    933	
    934	  // Is a given value an array?
    935	  // Delegates to ECMA5's native Array.isArray
    936	  _.isArray = nativeIsArray || function(obj) {
    937	    return toString.call(obj) == '[object Array]';
    938	  };
    939	
    940	  // Is a given variable an object?
    941	  _.isObject = function(obj) {
    942	    return obj === Object(obj);
    943	  };
    944	
    945	  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
    946	  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
    947	    _['is' + name] = function(obj) {
    948	      return toString.call(obj) == '[object ' + name + ']';
    949	    };
    950	  });
    951	
    952	  // Define a fallback version of the method in browsers (ahem, IE), where
    953	  // there isn't any inspectable "Arguments" type.
    954	  if (!_.isArguments(arguments)) {
    955	    _.isArguments = function(obj) {
    956	      return !!(obj && _.has(obj, 'callee'));
    957	    };
    958	  }
    959	
    960	  // Optimize `isFunction` if appropriate.
    961	  if (typeof (/./) !== 'function') {
    962	    _.isFunction = function(obj) {
    963	      return typeof obj === 'function';
    964	    };
    965	  }
    966	
    967	  // Is a given object a finite number?
    968	  _.isFinite = function(obj) {
    969	    return isFinite(obj) && !isNaN(parseFloat(obj));
    970	  };
    971	
    972	  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    973	  _.isNaN = function(obj) {
    974	    return _.isNumber(obj) && obj != +obj;
    975	  };
    976	
    977	  // Is a given value a boolean?
    978	  _.isBoolean = function(obj) {
    979	    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
    980	  };
    981	
    982	  // Is a given value equal to null?
    983	  _.isNull = function(obj) {
    984	    return obj === null;
    985	  };
    986	
    987	  // Is a given variable undefined?
    988	  _.isUndefined = function(obj) {
    989	    return obj === void 0;
    990	  };
    991	
    992	  // Shortcut function for checking if an object has a given property directly
    993	  // on itself (in other words, not on a prototype).
    994	  _.has = function(obj, key) {
    995	    return hasOwnProperty.call(obj, key);
    996	  };
    997	
    998	  // Utility Functions
    999	  // -----------------
    1000	
    1001	  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
    1002	  // previous owner. Returns a reference to the Underscore object.
    1003	  _.noConflict = function() {
    1004	    root._ = previousUnderscore;
    1005	    return this;
    1006	  };
    1007	
    1008	  // Keep the identity function around for default iterators.
    1009	  _.identity = function(value) {
    1010	    return value;
    1011	  };
    1012	
    1013	  // Run a function **n** times.
    1014	  _.times = function(n, iterator, context) {
    1015	    var accum = Array(n);
    1016	    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
    1017	    return accum;
    1018	  };
    1019	
    1020	  // Return a random integer between min and max (inclusive).
    1021	  _.random = function(min, max) {
    1022	    if (max == null) {
    1023	      max = min;
    1024	      min = 0;
    1025	    }
    1026	    return min + Math.floor(Math.random() * (max - min + 1));
    1027	  };
    1028	
    1029	  // List of HTML entities for escaping.
    1030	  var entityMap = {
    1031	    escape: {
    1032	      '&': '&amp;',
    1033	      '<': '&lt;',
    1034	      '>': '&gt;',
    1035	      '"': '&quot;',
    1036	      "'": '&#x27;',
    1037	      '/': '&#x2F;'
    1038	    }
    1039	  };
    1040	  entityMap.unescape = _.invert(entityMap.escape);
    1041	
    1042	  // Regexes containing the keys and values listed immediately above.
    1043	  var entityRegexes = {
    1044	    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
    1045	    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
    1046	  };
    1047	
    1048	  // Functions for escaping and unescaping strings to/from HTML interpolation.
    1049	  _.each(['escape', 'unescape'], function(method) {
    1050	    _[method] = function(string) {
    1051	      if (string == null) return '';
    1052	      return ('' + string).replace(entityRegexes[method], function(match) {
    1053	        return entityMap[method][match];
    1054	      });
    1055	    };
    1056	  });
    1057	
    1058	  // If the value of the named property is a function then invoke it;
    1059	  // otherwise, return it.
    1060	  _.result = function(object, property) {
    1061	    if (object == null) return null;
    1062	    var value = object[property];
    1063	    return _.isFunction(value) ? value.call(object) : value;
    1064	  };
    1065	
    1066	  // Add your own custom functions to the Underscore object.
    1067	  _.mixin = function(obj) {
    1068	    each(_.functions(obj), function(name){
    1069	      var func = _[name] = obj[name];
    1070	      _.prototype[name] = function() {
    1071	        var args = [this._wrapped];
    1072	        push.apply(args, arguments);
    1073	        return result.call(this, func.apply(_, args));
    1074	      };
    1075	    });
    1076	  };
    1077	
    1078	  // Generate a unique integer id (unique within the entire client session).
    1079	  // Useful for temporary DOM ids.
    1080	  var idCounter = 0;
    1081	  _.uniqueId = function(prefix) {
    1082	    var id = ++idCounter + '';
    1083	    return prefix ? prefix + id : id;
    1084	  };
    1085	
    1086	  // By default, Underscore uses ERB-style template delimiters, change the
    1087	  // following template settings to use alternative delimiters.
    1088	  _.templateSettings = {
    1089	    evaluate    : /<%([\s\S]+?)%>/g,
    1090	    interpolate : /<%=([\s\S]+?)%>/g,
    1091	    escape      : /<%-([\s\S]+?)%>/g
    1092	  };
    1093	
    1094	  // When customizing `templateSettings`, if you don't want to define an
    1095	  // interpolation, evaluation or escaping regex, we need one that is
    1096	  // guaranteed not to match.
    1097	  var noMatch = /(.)^/;
    1098	
    1099	  // Certain characters need to be escaped so that they can be put into a
    1100	  // string literal.
    1101	  var escapes = {
    1102	    "'":      "'",
    1103	    '\\':     '\\',
    1104	    '\r':     'r',
    1105	    '\n':     'n',
    1106	    '\t':     't',
    1107	    '\u2028': 'u2028',
    1108	    '\u2029': 'u2029'
    1109	  };
    1110	
    1111	  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
    1112	
    1113	  // JavaScript micro-templating, similar to John Resig's implementation.
    1114	  // Underscore templating handles arbitrary delimiters, preserves whitespace,
    1115	  // and correctly escapes quotes within interpolated code.
    1116	  _.template = function(text, data, settings) {
    1117	    var render;
    1118	    settings = _.defaults({}, settings, _.templateSettings);
    1119	
    1120	    // Combine delimiters into one regular expression via alternation.
    1121	    var matcher = new RegExp([
    1122	      (settings.escape || noMatch).source,
    1123	      (settings.interpolate || noMatch).source,
    1124	      (settings.evaluate || noMatch).source
    1125	    ].join('|') + '|$', 'g');
    1126	
    1127	    // Compile the template source, escaping string literals appropriately.
    1128	    var index = 0;
    1129	    var source = "__p+='";
    1130	    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
    1131	      source += text.slice(index, offset)
    1132	        .replace(escaper, function(match) { return '\\' + escapes[match]; });
    1133	
    1134	      if (escape) {
    1135	        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
    1136	      }
    1137	      if (interpolate) {
    1138	        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
    1139	      }
    1140	      if (evaluate) {
    1141	        source += "';\n" + evaluate + "\n__p+='";
    1142	      }
    1143	      index = offset + match.length;
    1144	      return match;
    1145	    });
    1146	    source += "';\n";
    1147	
    1148	    // If a variable is not specified, place data values in local scope.
    1149	    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
    1150	
    1151	    source = "var __t,__p='',__j=Array.prototype.join," +
    1152	      "print=function(){__p+=__j.call(arguments,'');};\n" +
    1153	      source + "return __p;\n";
    1154	
    1155	    try {
    1156	      render = new Function(settings.variable || 'obj', '_', source);
    1157	    } catch (e) {
    1158	      e.source = source;
    1159	      throw e;
    1160	    }
    1161	
    1162	    if (data) return render(data, _);
    1163	    var template = function(data) {
    1164	      return render.call(this, data, _);
    1165	    };
    1166	
    1167	    // Provide the compiled function source as a convenience for precompilation.
    1168	    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
    1169	
    1170	    return template;
    1171	  };
    1172	
    1173	  // Add a "chain" function, which will delegate to the wrapper.
    1174	  _.chain = function(obj) {
    1175	    return _(obj).chain();
    1176	  };
    1177	
    1178	  // OOP
    1179	  // ---------------
    1180	  // If Underscore is called as a function, it returns a wrapped object that
    1181	  // can be used OO-style. This wrapper holds altered versions of all the
    1182	  // underscore functions. Wrapped objects may be chained.
    1183	
    1184	  // Helper function to continue chaining intermediate results.
    1185	  var result = function(obj) {
    1186	    return this._chain ? _(obj).chain() : obj;
    1187	  };
    1188	
    1189	  // Add all of the Underscore functions to the wrapper object.
    1190	  _.mixin(_);
    1191	
    1192	  // Add all mutator Array functions to the wrapper.
    1193	  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    1194	    var method = ArrayProto[name];
    1195	    _.prototype[name] = function() {
    1196	      var obj = this._wrapped;
    1197	      method.apply(obj, arguments);
    1198	      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
    1199	      return result.call(this, obj);
    1200	    };
    1201	  });
    1202	
    1203	  // Add all accessor Array functions to the wrapper.
    1204	  each(['concat', 'join', 'slice'], function(name) {
    1205	    var method = ArrayProto[name];
    1206	    _.prototype[name] = function() {
    1207	      return result.call(this, method.apply(this._wrapped, arguments));
    1208	    };
    1209	  });
    1210	
    1211	  _.extend(_.prototype, {
    1212	
    1213	    // Start chaining a wrapped Underscore object.
    1214	    chain: function() {
    1215	      this._chain = true;
    1216	      return this;
    1217	    },
    1218	
    1219	    // Extracts the result from a wrapped and chained object.
    1220	    value: function() {
    1221	      return this._wrapped;
    1222	    }
    1223	
    1224	  });
    1225	
    1226	}).call(this);
  • WordPress 源代码——主干(underscore-1.4.1.js)

    WordPress 源代码——主干(underscore-1.4.1.js)

    //     Underscore.js 1.4.1
    2	//     http://underscorejs.org
    3	//     (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
    4	//     Underscore may be freely distributed under the MIT license.
    5	
    6	(function() {
    7	
    8	  // Baseline setup
    9	  // --------------
    10	
    11	  // Establish the root object, `window` in the browser, or `global` on the server.
    12	  var root = this;
    13	
    14	  // Save the previous value of the `_` variable.
    15	  var previousUnderscore = root._;
    16	
    17	  // Establish the object that gets returned to break out of a loop iteration.
    18	  var breaker = {};
    19	
    20	  // Save bytes in the minified (but not gzipped) version:
    21	  var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
    22	
    23	  // Create quick reference variables for speed access to core prototypes.
    24	  var push             = ArrayProto.push,
    25	      slice            = ArrayProto.slice,
    26	      concat           = ArrayProto.concat,
    27	      unshift          = ArrayProto.unshift,
    28	      toString         = ObjProto.toString,
    29	      hasOwnProperty   = ObjProto.hasOwnProperty;
    30	
    31	  // All **ECMAScript 5** native function implementations that we hope to use
    32	  // are declared here.
    33	  var
    34	    nativeForEach      = ArrayProto.forEach,
    35	    nativeMap          = ArrayProto.map,
    36	    nativeReduce       = ArrayProto.reduce,
    37	    nativeReduceRight  = ArrayProto.reduceRight,
    38	    nativeFilter       = ArrayProto.filter,
    39	    nativeEvery        = ArrayProto.every,
    40	    nativeSome         = ArrayProto.some,
    41	    nativeIndexOf      = ArrayProto.indexOf,
    42	    nativeLastIndexOf  = ArrayProto.lastIndexOf,
    43	    nativeIsArray      = Array.isArray,
    44	    nativeKeys         = Object.keys,
    45	    nativeBind         = FuncProto.bind;
    46	
    47	  // Create a safe reference to the Underscore object for use below.
    48	  var _ = function(obj) {
    49	    if (obj instanceof _) return obj;
    50	    if (!(this instanceof _)) return new _(obj);
    51	    this._wrapped = obj;
    52	  };
    53	
    54	  // Export the Underscore object for **Node.js**, with
    55	  // backwards-compatibility for the old `require()` API. If we're in
    56	  // the browser, add `_` as a global object via a string identifier,
    57	  // for Closure Compiler "advanced" mode.
    58	  if (typeof exports !== 'undefined') {
    59	    if (typeof module !== 'undefined' && module.exports) {
    60	      exports = module.exports = _;
    61	    }
    62	    exports._ = _;
    63	  } else {
    64	    root['_'] = _;
    65	  }
    66	
    67	  // Current version.
    68	  _.VERSION = '1.4.1';
    69	
    70	  // Collection Functions
    71	  // --------------------
    72	
    73	  // The cornerstone, an `each` implementation, aka `forEach`.
    74	  // Handles objects with the built-in `forEach`, arrays, and raw objects.
    75	  // Delegates to **ECMAScript 5**'s native `forEach` if available.
    76	  var each = _.each = _.forEach = function(obj, iterator, context) {
    77	    if (nativeForEach && obj.forEach === nativeForEach) {
    78	      obj.forEach(iterator, context);
    79	    } else if (obj.length === +obj.length) {
    80	      for (var i = 0, l = obj.length; i < l; i++) {
    81	        if (iterator.call(context, obj[i], i, obj) === breaker) return;
    82	      }
    83	    } else {
    84	      for (var key in obj) {
    85	        if (_.has(obj, key)) {
    86	          if (iterator.call(context, obj[key], key, obj) === breaker) return;
    87	        }
    88	      }
    89	    }
    90	  };
    91	
    92	  // Return the results of applying the iterator to each element.
    93	  // Delegates to **ECMAScript 5**'s native `map` if available.
    94	  _.map = _.collect = function(obj, iterator, context) {
    95	    var results = [];
    96	    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    97	    each(obj, function(value, index, list) {
    98	      results[results.length] = iterator.call(context, value, index, list);
    99	    });
    100	    return results;
    101	  };
    102	
    103	  // **Reduce** builds up a single result from a list of values, aka `inject`,
    104	  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
    105	  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    106	    var initial = arguments.length > 2;
    107	    if (nativeReduce && obj.reduce === nativeReduce) {
    108	      if (context) iterator = _.bind(iterator, context);
    109	      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    110	    }
    111	    each(obj, function(value, index, list) {
    112	      if (!initial) {
    113	        memo = value;
    114	        initial = true;
    115	      } else {
    116	        memo = iterator.call(context, memo, value, index, list);
    117	      }
    118	    });
    119	    if (!initial) throw new TypeError('Reduce of empty array with no initial value');
    120	    return memo;
    121	  };
    122	
    123	  // The right-associative version of reduce, also known as `foldr`.
    124	  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
    125	  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    126	    var initial = arguments.length > 2;
    127	    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
    128	      if (context) iterator = _.bind(iterator, context);
    129	      return arguments.length > 2 ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    130	    }
    131	    var length = obj.length;
    132	    if (length !== +length) {
    133	      var keys = _.keys(obj);
    134	      length = keys.length;
    135	    }
    136	    each(obj, function(value, index, list) {
    137	      index = keys ? keys[--length] : --length;
    138	      if (!initial) {
    139	        memo = obj[index];
    140	        initial = true;
    141	      } else {
    142	        memo = iterator.call(context, memo, obj[index], index, list);
    143	      }
    144	    });
    145	    if (!initial) throw new TypeError('Reduce of empty array with no initial value');
    146	    return memo;
    147	  };
    148	
    149	  // Return the first value which passes a truth test. Aliased as `detect`.
    150	  _.find = _.detect = function(obj, iterator, context) {
    151	    var result;
    152	    any(obj, function(value, index, list) {
    153	      if (iterator.call(context, value, index, list)) {
    154	        result = value;
    155	        return true;
    156	      }
    157	    });
    158	    return result;
    159	  };
    160	
    161	  // Return all the elements that pass a truth test.
    162	  // Delegates to **ECMAScript 5**'s native `filter` if available.
    163	  // Aliased as `select`.
    164	  _.filter = _.select = function(obj, iterator, context) {
    165	    var results = [];
    166	    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
    167	    each(obj, function(value, index, list) {
    168	      if (iterator.call(context, value, index, list)) results[results.length] = value;
    169	    });
    170	    return results;
    171	  };
    172	
    173	  // Return all the elements for which a truth test fails.
    174	  _.reject = function(obj, iterator, context) {
    175	    var results = [];
    176	    each(obj, function(value, index, list) {
    177	      if (!iterator.call(context, value, index, list)) results[results.length] = value;
    178	    });
    179	    return results;
    180	  };
    181	
    182	  // Determine whether all of the elements match a truth test.
    183	  // Delegates to **ECMAScript 5**'s native `every` if available.
    184	  // Aliased as `all`.
    185	  _.every = _.all = function(obj, iterator, context) {
    186	    iterator || (iterator = _.identity);
    187	    var result = true;
    188	    if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
    189	    each(obj, function(value, index, list) {
    190	      if (!(result = result && iterator.call(context, value, index, list))) return breaker;
    191	    });
    192	    return !!result;
    193	  };
    194	
    195	  // Determine if at least one element in the object matches a truth test.
    196	  // Delegates to **ECMAScript 5**'s native `some` if available.
    197	  // Aliased as `any`.
    198	  var any = _.some = _.any = function(obj, iterator, context) {
    199	    iterator || (iterator = _.identity);
    200	    var result = false;
    201	    if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
    202	    each(obj, function(value, index, list) {
    203	      if (result || (result = iterator.call(context, value, index, list))) return breaker;
    204	    });
    205	    return !!result;
    206	  };
    207	
    208	  // Determine if the array or object contains a given value (using `===`).
    209	  // Aliased as `include`.
    210	  _.contains = _.include = function(obj, target) {
    211	    var found = false;
    212	    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
    213	    found = any(obj, function(value) {
    214	      return value === target;
    215	    });
    216	    return found;
    217	  };
    218	
    219	  // Invoke a method (with arguments) on every item in a collection.
    220	  _.invoke = function(obj, method) {
    221	    var args = slice.call(arguments, 2);
    222	    return _.map(obj, function(value) {
    223	      return (_.isFunction(method) ? method : value[method]).apply(value, args);
    224	    });
    225	  };
    226	
    227	  // Convenience version of a common use case of `map`: fetching a property.
    228	  _.pluck = function(obj, key) {
    229	    return _.map(obj, function(value){ return value[key]; });
    230	  };
    231	
    232	  // Convenience version of a common use case of `filter`: selecting only objects
    233	  // with specific `key:value` pairs.
    234	  _.where = function(obj, attrs) {
    235	    if (_.isEmpty(attrs)) return [];
    236	    return _.filter(obj, function(value) {
    237	      for (var key in attrs) {
    238	        if (attrs[key] !== value[key]) return false;
    239	      }
    240	      return true;
    241	    });
    242	  };
    243	
    244	  // Return the maximum element or (element-based computation).
    245	  // Can't optimize arrays of integers longer than 65,535 elements.
    246	  // See: https://bugs.webkit.org/show_bug.cgi?id=80797
    247	  _.max = function(obj, iterator, context) {
    248	    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    249	      return Math.max.apply(Math, obj);
    250	    }
    251	    if (!iterator && _.isEmpty(obj)) return -Infinity;
    252	    var result = {computed : -Infinity};
    253	    each(obj, function(value, index, list) {
    254	      var computed = iterator ? iterator.call(context, value, index, list) : value;
    255	      computed >= result.computed && (result = {value : value, computed : computed});
    256	    });
    257	    return result.value;
    258	  };
    259	
    260	  // Return the minimum element (or element-based computation).
    261	  _.min = function(obj, iterator, context) {
    262	    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    263	      return Math.min.apply(Math, obj);
    264	    }
    265	    if (!iterator && _.isEmpty(obj)) return Infinity;
    266	    var result = {computed : Infinity};
    267	    each(obj, function(value, index, list) {
    268	      var computed = iterator ? iterator.call(context, value, index, list) : value;
    269	      computed < result.computed && (result = {value : value, computed : computed});
    270	    });
    271	    return result.value;
    272	  };
    273	
    274	  // Shuffle an array.
    275	  _.shuffle = function(obj) {
    276	    var rand;
    277	    var index = 0;
    278	    var shuffled = [];
    279	    each(obj, function(value) {
    280	      rand = _.random(index++);
    281	      shuffled[index - 1] = shuffled[rand];
    282	      shuffled[rand] = value;
    283	    });
    284	    return shuffled;
    285	  };
    286	
    287	  // An internal function to generate lookup iterators.
    288	  var lookupIterator = function(value) {
    289	    return _.isFunction(value) ? value : function(obj){ return obj[value]; };
    290	  };
    291	
    292	  // Sort the object's values by a criterion produced by an iterator.
    293	  _.sortBy = function(obj, value, context) {
    294	    var iterator = lookupIterator(value);
    295	    return _.pluck(_.map(obj, function(value, index, list) {
    296	      return {
    297	        value : value,
    298	        index : index,
    299	        criteria : iterator.call(context, value, index, list)
    300	      };
    301	    }).sort(function(left, right) {
    302	      var a = left.criteria;
    303	      var b = right.criteria;
    304	      if (a !== b) {
    305	        if (a > b || a === void 0) return 1;
    306	        if (a < b || b === void 0) return -1;
    307	      }
    308	      return left.index < right.index ? -1 : 1;
    309	    }), 'value');
    310	  };
    311	
    312	  // An internal function used for aggregate "group by" operations.
    313	  var group = function(obj, value, context, behavior) {
    314	    var result = {};
    315	    var iterator = lookupIterator(value);
    316	    each(obj, function(value, index) {
    317	      var key = iterator.call(context, value, index, obj);
    318	      behavior(result, key, value);
    319	    });
    320	    return result;
    321	  };
    322	
    323	  // Groups the object's values by a criterion. Pass either a string attribute
    324	  // to group by, or a function that returns the criterion.
    325	  _.groupBy = function(obj, value, context) {
    326	    return group(obj, value, context, function(result, key, value) {
    327	      (_.has(result, key) ? result[key] : (result[key] = [])).push(value);
    328	    });
    329	  };
    330	
    331	  // Counts instances of an object that group by a certain criterion. Pass
    332	  // either a string attribute to count by, or a function that returns the
    333	  // criterion.
    334	  _.countBy = function(obj, value, context) {
    335	    return group(obj, value, context, function(result, key, value) {
    336	      if (!_.has(result, key)) result[key] = 0;
    337	      result[key]++;
    338	    });
    339	  };
    340	
    341	  // Use a comparator function to figure out the smallest index at which
    342	  // an object should be inserted so as to maintain order. Uses binary search.
    343	  _.sortedIndex = function(array, obj, iterator, context) {
    344	    iterator = iterator == null ? _.identity : lookupIterator(iterator);
    345	    var value = iterator.call(context, obj);
    346	    var low = 0, high = array.length;
    347	    while (low < high) {
    348	      var mid = (low + high) >>> 1;
    349	      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
    350	    }
    351	    return low;
    352	  };
    353	
    354	  // Safely convert anything iterable into a real, live array.
    355	  _.toArray = function(obj) {
    356	    if (!obj) return [];
    357	    if (obj.length === +obj.length) return slice.call(obj);
    358	    return _.values(obj);
    359	  };
    360	
    361	  // Return the number of elements in an object.
    362	  _.size = function(obj) {
    363	    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
    364	  };
    365	
    366	  // Array Functions
    367	  // ---------------
    368	
    369	  // Get the first element of an array. Passing **n** will return the first N
    370	  // values in the array. Aliased as `head` and `take`. The **guard** check
    371	  // allows it to work with `_.map`.
    372	  _.first = _.head = _.take = function(array, n, guard) {
    373	    return (n != null) && !guard ? slice.call(array, 0, n) : array[0];
    374	  };
    375	
    376	  // Returns everything but the last entry of the array. Especially useful on
    377	  // the arguments object. Passing **n** will return all the values in
    378	  // the array, excluding the last N. The **guard** check allows it to work with
    379	  // `_.map`.
    380	  _.initial = function(array, n, guard) {
    381	    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
    382	  };
    383	
    384	  // Get the last element of an array. Passing **n** will return the last N
    385	  // values in the array. The **guard** check allows it to work with `_.map`.
    386	  _.last = function(array, n, guard) {
    387	    if ((n != null) && !guard) {
    388	      return slice.call(array, Math.max(array.length - n, 0));
    389	    } else {
    390	      return array[array.length - 1];
    391	    }
    392	  };
    393	
    394	  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    395	  // Especially useful on the arguments object. Passing an **n** will return
    396	  // the rest N values in the array. The **guard**
    397	  // check allows it to work with `_.map`.
    398	  _.rest = _.tail = _.drop = function(array, n, guard) {
    399	    return slice.call(array, (n == null) || guard ? 1 : n);
    400	  };
    401	
    402	  // Trim out all falsy values from an array.
    403	  _.compact = function(array) {
    404	    return _.filter(array, function(value){ return !!value; });
    405	  };
    406	
    407	  // Internal implementation of a recursive `flatten` function.
    408	  var flatten = function(input, shallow, output) {
    409	    each(input, function(value) {
    410	      if (_.isArray(value)) {
    411	        shallow ? push.apply(output, value) : flatten(value, shallow, output);
    412	      } else {
    413	        output.push(value);
    414	      }
    415	    });
    416	    return output;
    417	  };
    418	
    419	  // Return a completely flattened version of an array.
    420	  _.flatten = function(array, shallow) {
    421	    return flatten(array, shallow, []);
    422	  };
    423	
    424	  // Return a version of the array that does not contain the specified value(s).
    425	  _.without = function(array) {
    426	    return _.difference(array, slice.call(arguments, 1));
    427	  };
    428	
    429	  // Produce a duplicate-free version of the array. If the array has already
    430	  // been sorted, you have the option of using a faster algorithm.
    431	  // Aliased as `unique`.
    432	  _.uniq = _.unique = function(array, isSorted, iterator, context) {
    433	    var initial = iterator ? _.map(array, iterator, context) : array;
    434	    var results = [];
    435	    var seen = [];
    436	    each(initial, function(value, index) {
    437	      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
    438	        seen.push(value);
    439	        results.push(array[index]);
    440	      }
    441	    });
    442	    return results;
    443	  };
    444	
    445	  // Produce an array that contains the union: each distinct element from all of
    446	  // the passed-in arrays.
    447	  _.union = function() {
    448	    return _.uniq(concat.apply(ArrayProto, arguments));
    449	  };
    450	
    451	  // Produce an array that contains every item shared between all the
    452	  // passed-in arrays.
    453	  _.intersection = function(array) {
    454	    var rest = slice.call(arguments, 1);
    455	    return _.filter(_.uniq(array), function(item) {
    456	      return _.every(rest, function(other) {
    457	        return _.indexOf(other, item) >= 0;
    458	      });
    459	    });
    460	  };
    461	
    462	  // Take the difference between one array and a number of other arrays.
    463	  // Only the elements present in just the first array will remain.
    464	  _.difference = function(array) {
    465	    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
    466	    return _.filter(array, function(value){ return !_.contains(rest, value); });
    467	  };
    468	
    469	  // Zip together multiple lists into a single array -- elements that share
    470	  // an index go together.
    471	  _.zip = function() {
    472	    var args = slice.call(arguments);
    473	    var length = _.max(_.pluck(args, 'length'));
    474	    var results = new Array(length);
    475	    for (var i = 0; i < length; i++) {
    476	      results[i] = _.pluck(args, "" + i);
    477	    }
    478	    return results;
    479	  };
    480	
    481	  // Converts lists into objects. Pass either a single array of `[key, value]`
    482	  // pairs, or two parallel arrays of the same length -- one of keys, and one of
    483	  // the corresponding values.
    484	  _.object = function(list, values) {
    485	    var result = {};
    486	    for (var i = 0, l = list.length; i < l; i++) {
    487	      if (values) {
    488	        result[list[i]] = values[i];
    489	      } else {
    490	        result[list[i][0]] = list[i][1];
    491	      }
    492	    }
    493	    return result;
    494	  };
    495	
    496	  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
    497	  // we need this function. Return the position of the first occurrence of an
    498	  // item in an array, or -1 if the item is not included in the array.
    499	  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
    500	  // If the array is large and already in sort order, pass `true`
    501	  // for **isSorted** to use binary search.
    502	  _.indexOf = function(array, item, isSorted) {
    503	    var i = 0, l = array.length;
    504	    if (isSorted) {
    505	      if (typeof isSorted == 'number') {
    506	        i = (isSorted < 0 ? Math.max(0, l + isSorted) : isSorted);
    507	      } else {
    508	        i = _.sortedIndex(array, item);
    509	        return array[i] === item ? i : -1;
    510	      }
    511	    }
    512	    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    513	    for (; i < l; i++) if (array[i] === item) return i;
    514	    return -1;
    515	  };
    516	
    517	  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
    518	  _.lastIndexOf = function(array, item, from) {
    519	    var hasIndex = from != null;
    520	    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
    521	      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
    522	    }
    523	    var i = (hasIndex ? from : array.length);
    524	    while (i--) if (array[i] === item) return i;
    525	    return -1;
    526	  };
    527	
    528	  // Generate an integer Array containing an arithmetic progression. A port of
    529	  // the native Python `range()` function. See
    530	  // [the Python documentation](http://docs.python.org/library/functions.html#range).
    531	  _.range = function(start, stop, step) {
    532	    if (arguments.length <= 1) {
    533	      stop = start || 0;
    534	      start = 0;
    535	    }
    536	    step = arguments[2] || 1;
    537	
    538	    var len = Math.max(Math.ceil((stop - start) / step), 0);
    539	    var idx = 0;
    540	    var range = new Array(len);
    541	
    542	    while(idx < len) {
    543	      range[idx++] = start;
    544	      start += step;
    545	    }
    546	
    547	    return range;
    548	  };
    549	
    550	  // Function (ahem) Functions
    551	  // ------------------
    552	
    553	  // Reusable constructor function for prototype setting.
    554	  var ctor = function(){};
    555	
    556	  // Create a function bound to a given object (assigning `this`, and arguments,
    557	  // optionally). Binding with arguments is also known as `curry`.
    558	  // Delegates to **ECMAScript 5**'s native `Function.bind` if available.
    559	  // We check for `func.bind` first, to fail fast when `func` is undefined.
    560	  _.bind = function bind(func, context) {
    561	    var bound, args;
    562	    if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
    563	    if (!_.isFunction(func)) throw new TypeError;
    564	    args = slice.call(arguments, 2);
    565	    return bound = function() {
    566	      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
    567	      ctor.prototype = func.prototype;
    568	      var self = new ctor;
    569	      var result = func.apply(self, args.concat(slice.call(arguments)));
    570	      if (Object(result) === result) return result;
    571	      return self;
    572	    };
    573	  };
    574	
    575	  // Bind all of an object's methods to that object. Useful for ensuring that
    576	  // all callbacks defined on an object belong to it.
    577	  _.bindAll = function(obj) {
    578	    var funcs = slice.call(arguments, 1);
    579	    if (funcs.length == 0) funcs = _.functions(obj);
    580	    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
    581	    return obj;
    582	  };
    583	
    584	  // Memoize an expensive function by storing its results.
    585	  _.memoize = function(func, hasher) {
    586	    var memo = {};
    587	    hasher || (hasher = _.identity);
    588	    return function() {
    589	      var key = hasher.apply(this, arguments);
    590	      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
    591	    };
    592	  };
    593	
    594	  // Delays a function for the given number of milliseconds, and then calls
    595	  // it with the arguments supplied.
    596	  _.delay = function(func, wait) {
    597	    var args = slice.call(arguments, 2);
    598	    return setTimeout(function(){ return func.apply(null, args); }, wait);
    599	  };
    600	
    601	  // Defers a function, scheduling it to run after the current call stack has
    602	  // cleared.
    603	  _.defer = function(func) {
    604	    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
    605	  };
    606	
    607	  // Returns a function, that, when invoked, will only be triggered at most once
    608	  // during a given window of time.
    609	  _.throttle = function(func, wait) {
    610	    var context, args, timeout, throttling, more, result;
    611	    var whenDone = _.debounce(function(){ more = throttling = false; }, wait);
    612	    return function() {
    613	      context = this; args = arguments;
    614	      var later = function() {
    615	        timeout = null;
    616	        if (more) {
    617	          result = func.apply(context, args);
    618	        }
    619	        whenDone();
    620	      };
    621	      if (!timeout) timeout = setTimeout(later, wait);
    622	      if (throttling) {
    623	        more = true;
    624	      } else {
    625	        throttling = true;
    626	        result = func.apply(context, args);
    627	      }
    628	      whenDone();
    629	      return result;
    630	    };
    631	  };
    632	
    633	  // Returns a function, that, as long as it continues to be invoked, will not
    634	  // be triggered. The function will be called after it stops being called for
    635	  // N milliseconds. If `immediate` is passed, trigger the function on the
    636	  // leading edge, instead of the trailing.
    637	  _.debounce = function(func, wait, immediate) {
    638	    var timeout, result;
    639	    return function() {
    640	      var context = this, args = arguments;
    641	      var later = function() {
    642	        timeout = null;
    643	        if (!immediate) result = func.apply(context, args);
    644	      };
    645	      var callNow = immediate && !timeout;
    646	      clearTimeout(timeout);
    647	      timeout = setTimeout(later, wait);
    648	      if (callNow) result = func.apply(context, args);
    649	      return result;
    650	    };
    651	  };
    652	
    653	  // Returns a function that will be executed at most one time, no matter how
    654	  // often you call it. Useful for lazy initialization.
    655	  _.once = function(func) {
    656	    var ran = false, memo;
    657	    return function() {
    658	      if (ran) return memo;
    659	      ran = true;
    660	      memo = func.apply(this, arguments);
    661	      func = null;
    662	      return memo;
    663	    };
    664	  };
    665	
    666	  // Returns the first function passed as an argument to the second,
    667	  // allowing you to adjust arguments, run code before and after, and
    668	  // conditionally execute the original function.
    669	  _.wrap = function(func, wrapper) {
    670	    return function() {
    671	      var args = [func];
    672	      push.apply(args, arguments);
    673	      return wrapper.apply(this, args);
    674	    };
    675	  };
    676	
    677	  // Returns a function that is the composition of a list of functions, each
    678	  // consuming the return value of the function that follows.
    679	  _.compose = function() {
    680	    var funcs = arguments;
    681	    return function() {
    682	      var args = arguments;
    683	      for (var i = funcs.length - 1; i >= 0; i--) {
    684	        args = [funcs[i].apply(this, args)];
    685	      }
    686	      return args[0];
    687	    };
    688	  };
    689	
    690	  // Returns a function that will only be executed after being called N times.
    691	  _.after = function(times, func) {
    692	    if (times <= 0) return func();
    693	    return function() {
    694	      if (--times < 1) {
    695	        return func.apply(this, arguments);
    696	      }
    697	    };
    698	  };
    699	
    700	  // Object Functions
    701	  // ----------------
    702	
    703	  // Retrieve the names of an object's properties.
    704	  // Delegates to **ECMAScript 5**'s native `Object.keys`
    705	  _.keys = nativeKeys || function(obj) {
    706	    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    707	    var keys = [];
    708	    for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key;
    709	    return keys;
    710	  };
    711	
    712	  // Retrieve the values of an object's properties.
    713	  _.values = function(obj) {
    714	    var values = [];
    715	    for (var key in obj) if (_.has(obj, key)) values.push(obj[key]);
    716	    return values;
    717	  };
    718	
    719	  // Convert an object into a list of `[key, value]` pairs.
    720	  _.pairs = function(obj) {
    721	    var pairs = [];
    722	    for (var key in obj) if (_.has(obj, key)) pairs.push([key, obj[key]]);
    723	    return pairs;
    724	  };
    725	
    726	  // Invert the keys and values of an object. The values must be serializable.
    727	  _.invert = function(obj) {
    728	    var result = {};
    729	    for (var key in obj) if (_.has(obj, key)) result[obj[key]] = key;
    730	    return result;
    731	  };
    732	
    733	  // Return a sorted list of the function names available on the object.
    734	  // Aliased as `methods`
    735	  _.functions = _.methods = function(obj) {
    736	    var names = [];
    737	    for (var key in obj) {
    738	      if (_.isFunction(obj[key])) names.push(key);
    739	    }
    740	    return names.sort();
    741	  };
    742	
    743	  // Extend a given object with all the properties in passed-in object(s).
    744	  _.extend = function(obj) {
    745	    each(slice.call(arguments, 1), function(source) {
    746	      for (var prop in source) {
    747	        obj[prop] = source[prop];
    748	      }
    749	    });
    750	    return obj;
    751	  };
    752	
    753	  // Return a copy of the object only containing the whitelisted properties.
    754	  _.pick = function(obj) {
    755	    var copy = {};
    756	    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    757	    each(keys, function(key) {
    758	      if (key in obj) copy[key] = obj[key];
    759	    });
    760	    return copy;
    761	  };
    762	
    763	   // Return a copy of the object without the blacklisted properties.
    764	  _.omit = function(obj) {
    765	    var copy = {};
    766	    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    767	    for (var key in obj) {
    768	      if (!_.contains(keys, key)) copy[key] = obj[key];
    769	    }
    770	    return copy;
    771	  };
    772	
    773	  // Fill in a given object with default properties.
    774	  _.defaults = function(obj) {
    775	    each(slice.call(arguments, 1), function(source) {
    776	      for (var prop in source) {
    777	        if (obj[prop] == null) obj[prop] = source[prop];
    778	      }
    779	    });
    780	    return obj;
    781	  };
    782	
    783	  // Create a (shallow-cloned) duplicate of an object.
    784	  _.clone = function(obj) {
    785	    if (!_.isObject(obj)) return obj;
    786	    return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    787	  };
    788	
    789	  // Invokes interceptor with the obj, and then returns obj.
    790	  // The primary purpose of this method is to "tap into" a method chain, in
    791	  // order to perform operations on intermediate results within the chain.
    792	  _.tap = function(obj, interceptor) {
    793	    interceptor(obj);
    794	    return obj;
    795	  };
    796	
    797	  // Internal recursive comparison function for `isEqual`.
    798	  var eq = function(a, b, aStack, bStack) {
    799	    // Identical objects are equal. `0 === -0`, but they aren't identical.
    800	    // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal.
    801	    if (a === b) return a !== 0 || 1 / a == 1 / b;
    802	    // A strict comparison is necessary because `null == undefined`.
    803	    if (a == null || b == null) return a === b;
    804	    // Unwrap any wrapped objects.
    805	    if (a instanceof _) a = a._wrapped;
    806	    if (b instanceof _) b = b._wrapped;
    807	    // Compare `[[Class]]` names.
    808	    var className = toString.call(a);
    809	    if (className != toString.call(b)) return false;
    810	    switch (className) {
    811	      // Strings, numbers, dates, and booleans are compared by value.
    812	      case '[object String]':
    813	        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
    814	        // equivalent to `new String("5")`.
    815	        return a == String(b);
    816	      case '[object Number]':
    817	        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
    818	        // other numeric values.
    819	        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
    820	      case '[object Date]':
    821	      case '[object Boolean]':
    822	        // Coerce dates and booleans to numeric primitive values. Dates are compared by their
    823	        // millisecond representations. Note that invalid dates with millisecond representations
    824	        // of `NaN` are not equivalent.
    825	        return +a == +b;
    826	      // RegExps are compared by their source patterns and flags.
    827	      case '[object RegExp]':
    828	        return a.source == b.source &&
    829	               a.global == b.global &&
    830	               a.multiline == b.multiline &&
    831	               a.ignoreCase == b.ignoreCase;
    832	    }
    833	    if (typeof a != 'object' || typeof b != 'object') return false;
    834	    // Assume equality for cyclic structures. The algorithm for detecting cyclic
    835	    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
    836	    var length = aStack.length;
    837	    while (length--) {
    838	      // Linear search. Performance is inversely proportional to the number of
    839	      // unique nested structures.
    840	      if (aStack[length] == a) return bStack[length] == b;
    841	    }
    842	    // Add the first object to the stack of traversed objects.
    843	    aStack.push(a);
    844	    bStack.push(b);
    845	    var size = 0, result = true;
    846	    // Recursively compare objects and arrays.
    847	    if (className == '[object Array]') {
    848	      // Compare array lengths to determine if a deep comparison is necessary.
    849	      size = a.length;
    850	      result = size == b.length;
    851	      if (result) {
    852	        // Deep compare the contents, ignoring non-numeric properties.
    853	        while (size--) {
    854	          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
    855	        }
    856	      }
    857	    } else {
    858	      // Objects with different constructors are not equivalent, but `Object`s
    859	      // from different frames are.
    860	      var aCtor = a.constructor, bCtor = b.constructor;
    861	      if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
    862	                               _.isFunction(bCtor) && (bCtor instanceof bCtor))) {
    863	        return false;
    864	      }
    865	      // Deep compare objects.
    866	      for (var key in a) {
    867	        if (_.has(a, key)) {
    868	          // Count the expected number of properties.
    869	          size++;
    870	          // Deep compare each member.
    871	          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
    872	        }
    873	      }
    874	      // Ensure that both objects contain the same number of properties.
    875	      if (result) {
    876	        for (key in b) {
    877	          if (_.has(b, key) && !(size--)) break;
    878	        }
    879	        result = !size;
    880	      }
    881	    }
    882	    // Remove the first object from the stack of traversed objects.
    883	    aStack.pop();
    884	    bStack.pop();
    885	    return result;
    886	  };
    887	
    888	  // Perform a deep comparison to check if two objects are equal.
    889	  _.isEqual = function(a, b) {
    890	    return eq(a, b, [], []);
    891	  };
    892	
    893	  // Is a given array, string, or object empty?
    894	  // An "empty" object has no enumerable own-properties.
    895	  _.isEmpty = function(obj) {
    896	    if (obj == null) return true;
    897	    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
    898	    for (var key in obj) if (_.has(obj, key)) return false;
    899	    return true;
    900	  };
    901	
    902	  // Is a given value a DOM element?
    903	  _.isElement = function(obj) {
    904	    return !!(obj && obj.nodeType === 1);
    905	  };
    906	
    907	  // Is a given value an array?
    908	  // Delegates to ECMA5's native Array.isArray
    909	  _.isArray = nativeIsArray || function(obj) {
    910	    return toString.call(obj) == '[object Array]';
    911	  };
    912	
    913	  // Is a given variable an object?
    914	  _.isObject = function(obj) {
    915	    return obj === Object(obj);
    916	  };
    917	
    918	  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
    919	  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
    920	    _['is' + name] = function(obj) {
    921	      return toString.call(obj) == '[object ' + name + ']';
    922	    };
    923	  });
    924	
    925	  // Define a fallback version of the method in browsers (ahem, IE), where
    926	  // there isn't any inspectable "Arguments" type.
    927	  if (!_.isArguments(arguments)) {
    928	    _.isArguments = function(obj) {
    929	      return !!(obj && _.has(obj, 'callee'));
    930	    };
    931	  }
    932	
    933	  // Optimize `isFunction` if appropriate.
    934	  if (typeof (/./) !== 'function') {
    935	    _.isFunction = function(obj) {
    936	      return typeof obj === 'function';
    937	    };
    938	  }
    939	
    940	  // Is a given object a finite number?
    941	  _.isFinite = function(obj) {
    942	    return _.isNumber(obj) && isFinite(obj);
    943	  };
    944	
    945	  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    946	  _.isNaN = function(obj) {
    947	    return _.isNumber(obj) && obj != +obj;
    948	  };
    949	
    950	  // Is a given value a boolean?
    951	  _.isBoolean = function(obj) {
    952	    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
    953	  };
    954	
    955	  // Is a given value equal to null?
    956	  _.isNull = function(obj) {
    957	    return obj === null;
    958	  };
    959	
    960	  // Is a given variable undefined?
    961	  _.isUndefined = function(obj) {
    962	    return obj === void 0;
    963	  };
    964	
    965	  // Shortcut function for checking if an object has a given property directly
    966	  // on itself (in other words, not on a prototype).
    967	  _.has = function(obj, key) {
    968	    return hasOwnProperty.call(obj, key);
    969	  };
    970	
    971	  // Utility Functions
    972	  // -----------------
    973	
    974	  // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
    975	  // previous owner. Returns a reference to the Underscore object.
    976	  _.noConflict = function() {
    977	    root._ = previousUnderscore;
    978	    return this;
    979	  };
    980	
    981	  // Keep the identity function around for default iterators.
    982	  _.identity = function(value) {
    983	    return value;
    984	  };
    985	
    986	  // Run a function **n** times.
    987	  _.times = function(n, iterator, context) {
    988	    for (var i = 0; i < n; i++) iterator.call(context, i);
    989	  };
    990	
    991	  // Return a random integer between min and max (inclusive).
    992	  _.random = function(min, max) {
    993	    if (max == null) {
    994	      max = min;
    995	      min = 0;
    996	    }
    997	    return min + (0 | Math.random() * (max - min + 1));
    998	  };
    999	
    1000	  // List of HTML entities for escaping.
    1001	  var entityMap = {
    1002	    escape: {
    1003	      '&': '&amp;',
    1004	      '<': '&lt;',
    1005	      '>': '&gt;',
    1006	      '"': '&quot;',
    1007	      "'": '&#x27;',
    1008	      '/': '&#x2F;'
    1009	    }
    1010	  };
    1011	  entityMap.unescape = _.invert(entityMap.escape);
    1012	
    1013	  // Regexes containing the keys and values listed immediately above.
    1014	  var entityRegexes = {
    1015	    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
    1016	    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
    1017	  };
    1018	
    1019	  // Functions for escaping and unescaping strings to/from HTML interpolation.
    1020	  _.each(['escape', 'unescape'], function(method) {
    1021	    _[method] = function(string) {
    1022	      if (string == null) return '';
    1023	      return ('' + string).replace(entityRegexes[method], function(match) {
    1024	        return entityMap[method][match];
    1025	      });
    1026	    };
    1027	  });
    1028	
    1029	  // If the value of the named property is a function then invoke it;
    1030	  // otherwise, return it.
    1031	  _.result = function(object, property) {
    1032	    if (object == null) return null;
    1033	    var value = object[property];
    1034	    return _.isFunction(value) ? value.call(object) : value;
    1035	  };
    1036	
    1037	  // Add your own custom functions to the Underscore object.
    1038	  _.mixin = function(obj) {
    1039	    each(_.functions(obj), function(name){
    1040	      var func = _[name] = obj[name];
    1041	      _.prototype[name] = function() {
    1042	        var args = [this._wrapped];
    1043	        push.apply(args, arguments);
    1044	        return result.call(this, func.apply(_, args));
    1045	      };
    1046	    });
    1047	  };
    1048	
    1049	  // Generate a unique integer id (unique within the entire client session).
    1050	  // Useful for temporary DOM ids.
    1051	  var idCounter = 0;
    1052	  _.uniqueId = function(prefix) {
    1053	    var id = idCounter++;
    1054	    return prefix ? prefix + id : id;
    1055	  };
    1056	
    1057	  // By default, Underscore uses ERB-style template delimiters, change the
    1058	  // following template settings to use alternative delimiters.
    1059	  _.templateSettings = {
    1060	    evaluate    : /<%([\s\S]+?)%>/g,
    1061	    interpolate : /<%=([\s\S]+?)%>/g,
    1062	    escape      : /<%-([\s\S]+?)%>/g
    1063	  };
    1064	
    1065	  // When customizing `templateSettings`, if you don't want to define an
    1066	  // interpolation, evaluation or escaping regex, we need one that is
    1067	  // guaranteed not to match.
    1068	  var noMatch = /(.)^/;
    1069	
    1070	  // Certain characters need to be escaped so that they can be put into a
    1071	  // string literal.
    1072	  var escapes = {
    1073	    "'":      "'",
    1074	    '\\':     '\\',
    1075	    '\r':     'r',
    1076	    '\n':     'n',
    1077	    '\t':     't',
    1078	    '\u2028': 'u2028',
    1079	    '\u2029': 'u2029'
    1080	  };
    1081	
    1082	  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
    1083	
    1084	  // JavaScript micro-templating, similar to John Resig's implementation.
    1085	  // Underscore templating handles arbitrary delimiters, preserves whitespace,
    1086	  // and correctly escapes quotes within interpolated code.
    1087	  _.template = function(text, data, settings) {
    1088	    settings = _.defaults({}, settings, _.templateSettings);
    1089	
    1090	    // Combine delimiters into one regular expression via alternation.
    1091	    var matcher = new RegExp([
    1092	      (settings.escape || noMatch).source,
    1093	      (settings.interpolate || noMatch).source,
    1094	      (settings.evaluate || noMatch).source
    1095	    ].join('|') + '|$', 'g');
    1096	
    1097	    // Compile the template source, escaping string literals appropriately.
    1098	    var index = 0;
    1099	    var source = "__p+='";
    1100	    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
    1101	      source += text.slice(index, offset)
    1102	        .replace(escaper, function(match) { return '\\' + escapes[match]; });
    1103	      source +=
    1104	        escape ? "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'" :
    1105	        interpolate ? "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'" :
    1106	        evaluate ? "';\n" + evaluate + "\n__p+='" : '';
    1107	      index = offset + match.length;
    1108	    });
    1109	    source += "';\n";
    1110	
    1111	    // If a variable is not specified, place data values in local scope.
    1112	    if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
    1113	
    1114	    source = "var __t,__p='',__j=Array.prototype.join," +
    1115	      "print=function(){__p+=__j.call(arguments,'');};\n" +
    1116	      source + "return __p;\n";
    1117	
    1118	    try {
    1119	      var render = new Function(settings.variable || 'obj', '_', source);
    1120	    } catch (e) {
    1121	      e.source = source;
    1122	      throw e;
    1123	    }
    1124	
    1125	    if (data) return render(data, _);
    1126	    var template = function(data) {
    1127	      return render.call(this, data, _);
    1128	    };
    1129	
    1130	    // Provide the compiled function source as a convenience for precompilation.
    1131	    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
    1132	
    1133	    return template;
    1134	  };
    1135	
    1136	  // Add a "chain" function, which will delegate to the wrapper.
    1137	  _.chain = function(obj) {
    1138	    return _(obj).chain();
    1139	  };
    1140	
    1141	  // OOP
    1142	  // ---------------
    1143	  // If Underscore is called as a function, it returns a wrapped object that
    1144	  // can be used OO-style. This wrapper holds altered versions of all the
    1145	  // underscore functions. Wrapped objects may be chained.
    1146	
    1147	  // Helper function to continue chaining intermediate results.
    1148	  var result = function(obj) {
    1149	    return this._chain ? _(obj).chain() : obj;
    1150	  };
    1151	
    1152	  // Add all of the Underscore functions to the wrapper object.
    1153	  _.mixin(_);
    1154	
    1155	  // Add all mutator Array functions to the wrapper.
    1156	  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    1157	    var method = ArrayProto[name];
    1158	    _.prototype[name] = function() {
    1159	      var obj = this._wrapped;
    1160	      method.apply(obj, arguments);
    1161	      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
    1162	      return result.call(this, obj);
    1163	    };
    1164	  });
    1165	
    1166	  // Add all accessor Array functions to the wrapper.
    1167	  each(['concat', 'join', 'slice'], function(name) {
    1168	    var method = ArrayProto[name];
    1169	    _.prototype[name] = function() {
    1170	      return result.call(this, method.apply(this._wrapped, arguments));
    1171	    };
    1172	  });
    1173	
    1174	  _.extend(_.prototype, {
    1175	
    1176	    // Start chaining a wrapped Underscore object.
    1177	    chain: function() {
    1178	      this._chain = true;
    1179	      return this;
    1180	    },
    1181	
    1182	    // Extracts the result from a wrapped and chained object.
    1183	    value: function() {
    1184	      return this._wrapped;
    1185	    }
    1186	
    1187	  });
    1188	
    1189	}).call(this);
  • WordPress 源代码——主干(backbone-1.0.js)

    WordPress 源代码——主干(backbone-1.0.js)

    //     Backbone.js 1.0.0
    2	
    3	//     (c) 2010-2013 Jeremy Ashkenas, DocumentCloud Inc.
    4	//     Backbone may be freely distributed under the MIT license.
    5	//     For all details and documentation:
    6	//     http://backbonejs.org
    7	
    8	(function(){
    9	
    10	  // Initial Setup
    11	  // -------------
    12	
    13	  // Save a reference to the global object (`window` in the browser, `exports`
    14	  // on the server).
    15	  var root = this;
    16	
    17	  // Save the previous value of the `Backbone` variable, so that it can be
    18	  // restored later on, if `noConflict` is used.
    19	  var previousBackbone = root.Backbone;
    20	
    21	  // Create local references to array methods we'll want to use later.
    22	  var array = [];
    23	  var push = array.push;
    24	  var slice = array.slice;
    25	  var splice = array.splice;
    26	
    27	  // The top-level namespace. All public Backbone classes and modules will
    28	  // be attached to this. Exported for both the browser and the server.
    29	  var Backbone;
    30	  if (typeof exports !== 'undefined') {
    31	    Backbone = exports;
    32	  } else {
    33	    Backbone = root.Backbone = {};
    34	  }
    35	
    36	  // Current version of the library. Keep in sync with `package.json`.
    37	  Backbone.VERSION = '1.0.0';
    38	
    39	  // Require Underscore, if we're on the server, and it's not already present.
    40	  var _ = root._;
    41	  if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
    42	
    43	  // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
    44	  // the `$` variable.
    45	  Backbone.$ = root.jQuery || root.Zepto || root.ender || root.$;
    46	
    47	  // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
    48	  // to its previous owner. Returns a reference to this Backbone object.
    49	  Backbone.noConflict = function() {
    50	    root.Backbone = previousBackbone;
    51	    return this;
    52	  };
    53	
    54	  // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
    55	  // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
    56	  // set a `X-Http-Method-Override` header.
    57	  Backbone.emulateHTTP = false;
    58	
    59	  // Turn on `emulateJSON` to support legacy servers that can't deal with direct
    60	  // `application/json` requests ... will encode the body as
    61	  // `application/x-www-form-urlencoded` instead and will send the model in a
    62	  // form param named `model`.
    63	  Backbone.emulateJSON = false;
    64	
    65	  // Backbone.Events
    66	  // ---------------
    67	
    68	  // A module that can be mixed in to *any object* in order to provide it with
    69	  // custom events. You may bind with `on` or remove with `off` callback
    70	  // functions to an event; `trigger`-ing an event fires all callbacks in
    71	  // succession.
    72	  //
    73	  //     var object = {};
    74	  //     _.extend(object, Backbone.Events);
    75	  //     object.on('expand', function(){ alert('expanded'); });
    76	  //     object.trigger('expand');
    77	  //
    78	  var Events = Backbone.Events = {
    79	
    80	    // Bind an event to a `callback` function. Passing `"all"` will bind
    81	    // the callback to all events fired.
    82	    on: function(name, callback, context) {
    83	      if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
    84	      this._events || (this._events = {});
    85	      var events = this._events[name] || (this._events[name] = []);
    86	      events.push({callback: callback, context: context, ctx: context || this});
    87	      return this;
    88	    },
    89	
    90	    // Bind an event to only be triggered a single time. After the first time
    91	    // the callback is invoked, it will be removed.
    92	    once: function(name, callback, context) {
    93	      if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
    94	      var self = this;
    95	      var once = _.once(function() {
    96	        self.off(name, once);
    97	        callback.apply(this, arguments);
    98	      });
    99	      once._callback = callback;
    100	      return this.on(name, once, context);
    101	    },
    102	
    103	    // Remove one or many callbacks. If `context` is null, removes all
    104	    // callbacks with that function. If `callback` is null, removes all
    105	    // callbacks for the event. If `name` is null, removes all bound
    106	    // callbacks for all events.
    107	    off: function(name, callback, context) {
    108	      var retain, ev, events, names, i, l, j, k;
    109	      if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
    110	      if (!name && !callback && !context) {
    111	        this._events = {};
    112	        return this;
    113	      }
    114	
    115	      names = name ? [name] : _.keys(this._events);
    116	      for (i = 0, l = names.length; i < l; i++) {
    117	        name = names[i];
    118	        if (events = this._events[name]) {
    119	          this._events[name] = retain = [];
    120	          if (callback || context) {
    121	            for (j = 0, k = events.length; j < k; j++) {
    122	              ev = events[j];
    123	              if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
    124	                  (context && context !== ev.context)) {
    125	                retain.push(ev);
    126	              }
    127	            }
    128	          }
    129	          if (!retain.length) delete this._events[name];
    130	        }
    131	      }
    132	
    133	      return this;
    134	    },
    135	
    136	    // Trigger one or many events, firing all bound callbacks. Callbacks are
    137	    // passed the same arguments as `trigger` is, apart from the event name
    138	    // (unless you're listening on `"all"`, which will cause your callback to
    139	    // receive the true name of the event as the first argument).
    140	    trigger: function(name) {
    141	      if (!this._events) return this;
    142	      var args = slice.call(arguments, 1);
    143	      if (!eventsApi(this, 'trigger', name, args)) return this;
    144	      var events = this._events[name];
    145	      var allEvents = this._events.all;
    146	      if (events) triggerEvents(events, args);
    147	      if (allEvents) triggerEvents(allEvents, arguments);
    148	      return this;
    149	    },
    150	
    151	    // Tell this object to stop listening to either specific events ... or
    152	    // to every object it's currently listening to.
    153	    stopListening: function(obj, name, callback) {
    154	      var listeners = this._listeners;
    155	      if (!listeners) return this;
    156	      var deleteListener = !name && !callback;
    157	      if (typeof name === 'object') callback = this;
    158	      if (obj) (listeners = {})[obj._listenerId] = obj;
    159	      for (var id in listeners) {
    160	        listeners[id].off(name, callback, this);
    161	        if (deleteListener) delete this._listeners[id];
    162	      }
    163	      return this;
    164	    }
    165	
    166	  };
    167	
    168	  // Regular expression used to split event strings.
    169	  var eventSplitter = /\s+/;
    170	
    171	  // Implement fancy features of the Events API such as multiple event
    172	  // names `"change blur"` and jQuery-style event maps `{change: action}`
    173	  // in terms of the existing API.
    174	  var eventsApi = function(obj, action, name, rest) {
    175	    if (!name) return true;
    176	
    177	    // Handle event maps.
    178	    if (typeof name === 'object') {
    179	      for (var key in name) {
    180	        obj[action].apply(obj, [key, name[key]].concat(rest));
    181	      }
    182	      return false;
    183	    }
    184	
    185	    // Handle space separated event names.
    186	    if (eventSplitter.test(name)) {
    187	      var names = name.split(eventSplitter);
    188	      for (var i = 0, l = names.length; i < l; i++) {
    189	        obj[action].apply(obj, [names[i]].concat(rest));
    190	      }
    191	      return false;
    192	    }
    193	
    194	    return true;
    195	  };
    196	
    197	  // A difficult-to-believe, but optimized internal dispatch function for
    198	  // triggering events. Tries to keep the usual cases speedy (most internal
    199	  // Backbone events have 3 arguments).
    200	  var triggerEvents = function(events, args) {
    201	    var ev, i = -1, l = events.length, a1 = args[0], a2 = args[1], a3 = args[2];
    202	    switch (args.length) {
    203	      case 0: while (++i < l) (ev = events[i]).callback.call(ev.ctx); return;
    204	      case 1: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1); return;
    205	      case 2: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2); return;
    206	      case 3: while (++i < l) (ev = events[i]).callback.call(ev.ctx, a1, a2, a3); return;
    207	      default: while (++i < l) (ev = events[i]).callback.apply(ev.ctx, args);
    208	    }
    209	  };
    210	
    211	  var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
    212	
    213	  // Inversion-of-control versions of `on` and `once`. Tell *this* object to
    214	  // listen to an event in another object ... keeping track of what it's
    215	  // listening to.
    216	  _.each(listenMethods, function(implementation, method) {
    217	    Events[method] = function(obj, name, callback) {
    218	      var listeners = this._listeners || (this._listeners = {});
    219	      var id = obj._listenerId || (obj._listenerId = _.uniqueId('l'));
    220	      listeners[id] = obj;
    221	      if (typeof name === 'object') callback = this;
    222	      obj[implementation](name, callback, this);
    223	      return this;
    224	    };
    225	  });
    226	
    227	  // Aliases for backwards compatibility.
    228	  Events.bind   = Events.on;
    229	  Events.unbind = Events.off;
    230	
    231	  // Allow the `Backbone` object to serve as a global event bus, for folks who
    232	  // want global "pubsub" in a convenient place.
    233	  _.extend(Backbone, Events);
    234	
    235	  // Backbone.Model
    236	  // --------------
    237	
    238	  // Backbone **Models** are the basic data object in the framework --
    239	  // frequently representing a row in a table in a database on your server.
    240	  // A discrete chunk of data and a bunch of useful, related methods for
    241	  // performing computations and transformations on that data.
    242	
    243	  // Create a new model with the specified attributes. A client id (`cid`)
    244	  // is automatically generated and assigned for you.
    245	  var Model = Backbone.Model = function(attributes, options) {
    246	    var defaults;
    247	    var attrs = attributes || {};
    248	    options || (options = {});
    249	    this.cid = _.uniqueId('c');
    250	    this.attributes = {};
    251	    _.extend(this, _.pick(options, modelOptions));
    252	    if (options.parse) attrs = this.parse(attrs, options) || {};
    253	    if (defaults = _.result(this, 'defaults')) {
    254	      attrs = _.defaults({}, attrs, defaults);
    255	    }
    256	    this.set(attrs, options);
    257	    this.changed = {};
    258	    this.initialize.apply(this, arguments);
    259	  };
    260	
    261	  // A list of options to be attached directly to the model, if provided.
    262	  var modelOptions = ['url', 'urlRoot', 'collection'];
    263	
    264	  // Attach all inheritable methods to the Model prototype.
    265	  _.extend(Model.prototype, Events, {
    266	
    267	    // A hash of attributes whose current and previous value differ.
    268	    changed: null,
    269	
    270	    // The value returned during the last failed validation.
    271	    validationError: null,
    272	
    273	    // The default name for the JSON `id` attribute is `"id"`. MongoDB and
    274	    // CouchDB users may want to set this to `"_id"`.
    275	    idAttribute: 'id',
    276	
    277	    // Initialize is an empty function by default. Override it with your own
    278	    // initialization logic.
    279	    initialize: function(){},
    280	
    281	    // Return a copy of the model's `attributes` object.
    282	    toJSON: function(options) {
    283	      return _.clone(this.attributes);
    284	    },
    285	
    286	    // Proxy `Backbone.sync` by default -- but override this if you need
    287	    // custom syncing semantics for *this* particular model.
    288	    sync: function() {
    289	      return Backbone.sync.apply(this, arguments);
    290	    },
    291	
    292	    // Get the value of an attribute.
    293	    get: function(attr) {
    294	      return this.attributes[attr];
    295	    },
    296	
    297	    // Get the HTML-escaped value of an attribute.
    298	    escape: function(attr) {
    299	      return _.escape(this.get(attr));
    300	    },
    301	
    302	    // Returns `true` if the attribute contains a value that is not null
    303	    // or undefined.
    304	    has: function(attr) {
    305	      return this.get(attr) != null;
    306	    },
    307	
    308	    // Set a hash of model attributes on the object, firing `"change"`. This is
    309	    // the core primitive operation of a model, updating the data and notifying
    310	    // anyone who needs to know about the change in state. The heart of the beast.
    311	    set: function(key, val, options) {
    312	      var attr, attrs, unset, changes, silent, changing, prev, current;
    313	      if (key == null) return this;
    314	
    315	      // Handle both `"key", value` and `{key: value}` -style arguments.
    316	      if (typeof key === 'object') {
    317	        attrs = key;
    318	        options = val;
    319	      } else {
    320	        (attrs = {})[key] = val;
    321	      }
    322	
    323	      options || (options = {});
    324	
    325	      // Run validation.
    326	      if (!this._validate(attrs, options)) return false;
    327	
    328	      // Extract attributes and options.
    329	      unset           = options.unset;
    330	      silent          = options.silent;
    331	      changes         = [];
    332	      changing        = this._changing;
    333	      this._changing  = true;
    334	
    335	      if (!changing) {
    336	        this._previousAttributes = _.clone(this.attributes);
    337	        this.changed = {};
    338	      }
    339	      current = this.attributes, prev = this._previousAttributes;
    340	
    341	      // Check for changes of `id`.
    342	      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
    343	
    344	      // For each `set` attribute, update or delete the current value.
    345	      for (attr in attrs) {
    346	        val = attrs[attr];
    347	        if (!_.isEqual(current[attr], val)) changes.push(attr);
    348	        if (!_.isEqual(prev[attr], val)) {
    349	          this.changed[attr] = val;
    350	        } else {
    351	          delete this.changed[attr];
    352	        }
    353	        unset ? delete current[attr] : current[attr] = val;
    354	      }
    355	
    356	      // Trigger all relevant attribute changes.
    357	      if (!silent) {
    358	        if (changes.length) this._pending = true;
    359	        for (var i = 0, l = changes.length; i < l; i++) {
    360	          this.trigger('change:' + changes[i], this, current[changes[i]], options);
    361	        }
    362	      }
    363	
    364	      // You might be wondering why there's a `while` loop here. Changes can
    365	      // be recursively nested within `"change"` events.
    366	      if (changing) return this;
    367	      if (!silent) {
    368	        while (this._pending) {
    369	          this._pending = false;
    370	          this.trigger('change', this, options);
    371	        }
    372	      }
    373	      this._pending = false;
    374	      this._changing = false;
    375	      return this;
    376	    },
    377	
    378	    // Remove an attribute from the model, firing `"change"`. `unset` is a noop
    379	    // if the attribute doesn't exist.
    380	    unset: function(attr, options) {
    381	      return this.set(attr, void 0, _.extend({}, options, {unset: true}));
    382	    },
    383	
    384	    // Clear all attributes on the model, firing `"change"`.
    385	    clear: function(options) {
    386	      var attrs = {};
    387	      for (var key in this.attributes) attrs[key] = void 0;
    388	      return this.set(attrs, _.extend({}, options, {unset: true}));
    389	    },
    390	
    391	    // Determine if the model has changed since the last `"change"` event.
    392	    // If you specify an attribute name, determine if that attribute has changed.
    393	    hasChanged: function(attr) {
    394	      if (attr == null) return !_.isEmpty(this.changed);
    395	      return _.has(this.changed, attr);
    396	    },
    397	
    398	    // Return an object containing all the attributes that have changed, or
    399	    // false if there are no changed attributes. Useful for determining what
    400	    // parts of a view need to be updated and/or what attributes need to be
    401	    // persisted to the server. Unset attributes will be set to undefined.
    402	    // You can also pass an attributes object to diff against the model,
    403	    // determining if there *would be* a change.
    404	    changedAttributes: function(diff) {
    405	      if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
    406	      var val, changed = false;
    407	      var old = this._changing ? this._previousAttributes : this.attributes;
    408	      for (var attr in diff) {
    409	        if (_.isEqual(old[attr], (val = diff[attr]))) continue;
    410	        (changed || (changed = {}))[attr] = val;
    411	      }
    412	      return changed;
    413	    },
    414	
    415	    // Get the previous value of an attribute, recorded at the time the last
    416	    // `"change"` event was fired.
    417	    previous: function(attr) {
    418	      if (attr == null || !this._previousAttributes) return null;
    419	      return this._previousAttributes[attr];
    420	    },
    421	
    422	    // Get all of the attributes of the model at the time of the previous
    423	    // `"change"` event.
    424	    previousAttributes: function() {
    425	      return _.clone(this._previousAttributes);
    426	    },
    427	
    428	    // Fetch the model from the server. If the server's representation of the
    429	    // model differs from its current attributes, they will be overridden,
    430	    // triggering a `"change"` event.
    431	    fetch: function(options) {
    432	      options = options ? _.clone(options) : {};
    433	      if (options.parse === void 0) options.parse = true;
    434	      var model = this;
    435	      var success = options.success;
    436	      options.success = function(resp) {
    437	        if (!model.set(model.parse(resp, options), options)) return false;
    438	        if (success) success(model, resp, options);
    439	        model.trigger('sync', model, resp, options);
    440	      };
    441	      wrapError(this, options);
    442	      return this.sync('read', this, options);
    443	    },
    444	
    445	    // Set a hash of model attributes, and sync the model to the server.
    446	    // If the server returns an attributes hash that differs, the model's
    447	    // state will be `set` again.
    448	    save: function(key, val, options) {
    449	      var attrs, method, xhr, attributes = this.attributes;
    450	
    451	      // Handle both `"key", value` and `{key: value}` -style arguments.
    452	      if (key == null || typeof key === 'object') {
    453	        attrs = key;
    454	        options = val;
    455	      } else {
    456	        (attrs = {})[key] = val;
    457	      }
    458	
    459	      // If we're not waiting and attributes exist, save acts as `set(attr).save(null, opts)`.
    460	      if (attrs && (!options || !options.wait) && !this.set(attrs, options)) return false;
    461	
    462	      options = _.extend({validate: true}, options);
    463	
    464	      // Do not persist invalid models.
    465	      if (!this._validate(attrs, options)) return false;
    466	
    467	      // Set temporary attributes if `{wait: true}`.
    468	      if (attrs && options.wait) {
    469	        this.attributes = _.extend({}, attributes, attrs);
    470	      }
    471	
    472	      // After a successful server-side save, the client is (optionally)
    473	      // updated with the server-side state.
    474	      if (options.parse === void 0) options.parse = true;
    475	      var model = this;
    476	      var success = options.success;
    477	      options.success = function(resp) {
    478	        // Ensure attributes are restored during synchronous saves.
    479	        model.attributes = attributes;
    480	        var serverAttrs = model.parse(resp, options);
    481	        if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
    482	        if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
    483	          return false;
    484	        }
    485	        if (success) success(model, resp, options);
    486	        model.trigger('sync', model, resp, options);
    487	      };
    488	      wrapError(this, options);
    489	
    490	      method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
    491	      if (method === 'patch') options.attrs = attrs;
    492	      xhr = this.sync(method, this, options);
    493	
    494	      // Restore attributes.
    495	      if (attrs && options.wait) this.attributes = attributes;
    496	
    497	      return xhr;
    498	    },
    499	
    500	    // Destroy this model on the server if it was already persisted.
    501	    // Optimistically removes the model from its collection, if it has one.
    502	    // If `wait: true` is passed, waits for the server to respond before removal.
    503	    destroy: function(options) {
    504	      options = options ? _.clone(options) : {};
    505	      var model = this;
    506	      var success = options.success;
    507	
    508	      var destroy = function() {
    509	        model.trigger('destroy', model, model.collection, options);
    510	      };
    511	
    512	      options.success = function(resp) {
    513	        if (options.wait || model.isNew()) destroy();
    514	        if (success) success(model, resp, options);
    515	        if (!model.isNew()) model.trigger('sync', model, resp, options);
    516	      };
    517	
    518	      if (this.isNew()) {
    519	        options.success();
    520	        return false;
    521	      }
    522	      wrapError(this, options);
    523	
    524	      var xhr = this.sync('delete', this, options);
    525	      if (!options.wait) destroy();
    526	      return xhr;
    527	    },
    528	
    529	    // Default URL for the model's representation on the server -- if you're
    530	    // using Backbone's restful methods, override this to change the endpoint
    531	    // that will be called.
    532	    url: function() {
    533	      var base = _.result(this, 'urlRoot') || _.result(this.collection, 'url') || urlError();
    534	      if (this.isNew()) return base;
    535	      return base + (base.charAt(base.length - 1) === '/' ? '' : '/') + encodeURIComponent(this.id);
    536	    },
    537	
    538	    // **parse** converts a response into the hash of attributes to be `set` on
    539	    // the model. The default implementation is just to pass the response along.
    540	    parse: function(resp, options) {
    541	      return resp;
    542	    },
    543	
    544	    // Create a new model with identical attributes to this one.
    545	    clone: function() {
    546	      return new this.constructor(this.attributes);
    547	    },
    548	
    549	    // A model is new if it has never been saved to the server, and lacks an id.
    550	    isNew: function() {
    551	      return this.id == null;
    552	    },
    553	
    554	    // Check if the model is currently in a valid state.
    555	    isValid: function(options) {
    556	      return this._validate({}, _.extend(options || {}, { validate: true }));
    557	    },
    558	
    559	    // Run validation against the next complete set of model attributes,
    560	    // returning `true` if all is well. Otherwise, fire an `"invalid"` event.
    561	    _validate: function(attrs, options) {
    562	      if (!options.validate || !this.validate) return true;
    563	      attrs = _.extend({}, this.attributes, attrs);
    564	      var error = this.validationError = this.validate(attrs, options) || null;
    565	      if (!error) return true;
    566	      this.trigger('invalid', this, error, _.extend(options || {}, {validationError: error}));
    567	      return false;
    568	    }
    569	
    570	  });
    571	
    572	  // Underscore methods that we want to implement on the Model.
    573	  var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
    574	
    575	  // Mix in each Underscore method as a proxy to `Model#attributes`.
    576	  _.each(modelMethods, function(method) {
    577	    Model.prototype[method] = function() {
    578	      var args = slice.call(arguments);
    579	      args.unshift(this.attributes);
    580	      return _[method].apply(_, args);
    581	    };
    582	  });
    583	
    584	  // Backbone.Collection
    585	  // -------------------
    586	
    587	  // If models tend to represent a single row of data, a Backbone Collection is
    588	  // more analagous to a table full of data ... or a small slice or page of that
    589	  // table, or a collection of rows that belong together for a particular reason
    590	  // -- all of the messages in this particular folder, all of the documents
    591	  // belonging to this particular author, and so on. Collections maintain
    592	  // indexes of their models, both in order, and for lookup by `id`.
    593	
    594	  // Create a new **Collection**, perhaps to contain a specific type of `model`.
    595	  // If a `comparator` is specified, the Collection will maintain
    596	  // its models in sort order, as they're added and removed.
    597	  var Collection = Backbone.Collection = function(models, options) {
    598	    options || (options = {});
    599	    if (options.url) this.url = options.url;
    600	    if (options.model) this.model = options.model;
    601	    if (options.comparator !== void 0) this.comparator = options.comparator;
    602	    this._reset();
    603	    this.initialize.apply(this, arguments);
    604	    if (models) this.reset(models, _.extend({silent: true}, options));
    605	  };
    606	
    607	  // Default options for `Collection#set`.
    608	  var setOptions = {add: true, remove: true, merge: true};
    609	  var addOptions = {add: true, merge: false, remove: false};
    610	
    611	  // Define the Collection's inheritable methods.
    612	  _.extend(Collection.prototype, Events, {
    613	
    614	    // The default model for a collection is just a **Backbone.Model**.
    615	    // This should be overridden in most cases.
    616	    model: Model,
    617	
    618	    // Initialize is an empty function by default. Override it with your own
    619	    // initialization logic.
    620	    initialize: function(){},
    621	
    622	    // The JSON representation of a Collection is an array of the
    623	    // models' attributes.
    624	    toJSON: function(options) {
    625	      return this.map(function(model){ return model.toJSON(options); });
    626	    },
    627	
    628	    // Proxy `Backbone.sync` by default.
    629	    sync: function() {
    630	      return Backbone.sync.apply(this, arguments);
    631	    },
    632	
    633	    // Add a model, or list of models to the set.
    634	    add: function(models, options) {
    635	      return this.set(models, _.defaults(options || {}, addOptions));
    636	    },
    637	
    638	    // Remove a model, or a list of models from the set.
    639	    remove: function(models, options) {
    640	      models = _.isArray(models) ? models.slice() : [models];
    641	      options || (options = {});
    642	      var i, l, index, model;
    643	      for (i = 0, l = models.length; i < l; i++) {
    644	        model = this.get(models[i]);
    645	        if (!model) continue;
    646	        delete this._byId[model.id];
    647	        delete this._byId[model.cid];
    648	        index = this.indexOf(model);
    649	        this.models.splice(index, 1);
    650	        this.length--;
    651	        if (!options.silent) {
    652	          options.index = index;
    653	          model.trigger('remove', model, this, options);
    654	        }
    655	        this._removeReference(model);
    656	      }
    657	      return this;
    658	    },
    659	
    660	    // Update a collection by `set`-ing a new list of models, adding new ones,
    661	    // removing models that are no longer present, and merging models that
    662	    // already exist in the collection, as necessary. Similar to **Model#set**,
    663	    // the core operation for updating the data contained by the collection.
    664	    set: function(models, options) {
    665	      options = _.defaults(options || {}, setOptions);
    666	      if (options.parse) models = this.parse(models, options);
    667	      if (!_.isArray(models)) models = models ? [models] : [];
    668	      var i, l, model, attrs, existing, sort;
    669	      var at = options.at;
    670	      var sortable = this.comparator && (at == null) && options.sort !== false;
    671	      var sortAttr = _.isString(this.comparator) ? this.comparator : null;
    672	      var toAdd = [], toRemove = [], modelMap = {};
    673	
    674	      // Turn bare objects into model references, and prevent invalid models
    675	      // from being added.
    676	      for (i = 0, l = models.length; i < l; i++) {
    677	        if (!(model = this._prepareModel(models[i], options))) continue;
    678	
    679	        // If a duplicate is found, prevent it from being added and
    680	        // optionally merge it into the existing model.
    681	        if (existing = this.get(model)) {
    682	          if (options.remove) modelMap[existing.cid] = true;
    683	          if (options.merge) {
    684	            existing.set(model.attributes, options);
    685	            if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
    686	          }
    687	
    688	        // This is a new model, push it to the `toAdd` list.
    689	        } else if (options.add) {
    690	          toAdd.push(model);
    691	
    692	          // Listen to added models' events, and index models for lookup by
    693	          // `id` and by `cid`.
    694	          model.on('all', this._onModelEvent, this);
    695	          this._byId[model.cid] = model;
    696	          if (model.id != null) this._byId[model.id] = model;
    697	        }
    698	      }
    699	
    700	      // Remove nonexistent models if appropriate.
    701	      if (options.remove) {
    702	        for (i = 0, l = this.length; i < l; ++i) {
    703	          if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
    704	        }
    705	        if (toRemove.length) this.remove(toRemove, options);
    706	      }
    707	
    708	      // See if sorting is needed, update `length` and splice in new models.
    709	      if (toAdd.length) {
    710	        if (sortable) sort = true;
    711	        this.length += toAdd.length;
    712	        if (at != null) {
    713	          splice.apply(this.models, [at, 0].concat(toAdd));
    714	        } else {
    715	          push.apply(this.models, toAdd);
    716	        }
    717	      }
    718	
    719	      // Silently sort the collection if appropriate.
    720	      if (sort) this.sort({silent: true});
    721	
    722	      if (options.silent) return this;
    723	
    724	      // Trigger `add` events.
    725	      for (i = 0, l = toAdd.length; i < l; i++) {
    726	        (model = toAdd[i]).trigger('add', model, this, options);
    727	      }
    728	
    729	      // Trigger `sort` if the collection was sorted.
    730	      if (sort) this.trigger('sort', this, options);
    731	      return this;
    732	    },
    733	
    734	    // When you have more items than you want to add or remove individually,
    735	    // you can reset the entire set with a new list of models, without firing
    736	    // any granular `add` or `remove` events. Fires `reset` when finished.
    737	    // Useful for bulk operations and optimizations.
    738	    reset: function(models, options) {
    739	      options || (options = {});
    740	      for (var i = 0, l = this.models.length; i < l; i++) {
    741	        this._removeReference(this.models[i]);
    742	      }
    743	      options.previousModels = this.models;
    744	      this._reset();
    745	      this.add(models, _.extend({silent: true}, options));
    746	      if (!options.silent) this.trigger('reset', this, options);
    747	      return this;
    748	    },
    749	
    750	    // Add a model to the end of the collection.
    751	    push: function(model, options) {
    752	      model = this._prepareModel(model, options);
    753	      this.add(model, _.extend({at: this.length}, options));
    754	      return model;
    755	    },
    756	
    757	    // Remove a model from the end of the collection.
    758	    pop: function(options) {
    759	      var model = this.at(this.length - 1);
    760	      this.remove(model, options);
    761	      return model;
    762	    },
    763	
    764	    // Add a model to the beginning of the collection.
    765	    unshift: function(model, options) {
    766	      model = this._prepareModel(model, options);
    767	      this.add(model, _.extend({at: 0}, options));
    768	      return model;
    769	    },
    770	
    771	    // Remove a model from the beginning of the collection.
    772	    shift: function(options) {
    773	      var model = this.at(0);
    774	      this.remove(model, options);
    775	      return model;
    776	    },
    777	
    778	    // Slice out a sub-array of models from the collection.
    779	    slice: function(begin, end) {
    780	      return this.models.slice(begin, end);
    781	    },
    782	
    783	    // Get a model from the set by id.
    784	    get: function(obj) {
    785	      if (obj == null) return void 0;
    786	      return this._byId[obj.id != null ? obj.id : obj.cid || obj];
    787	    },
    788	
    789	    // Get the model at the given index.
    790	    at: function(index) {
    791	      return this.models[index];
    792	    },
    793	
    794	    // Return models with matching attributes. Useful for simple cases of
    795	    // `filter`.
    796	    where: function(attrs, first) {
    797	      if (_.isEmpty(attrs)) return first ? void 0 : [];
    798	      return this[first ? 'find' : 'filter'](function(model) {
    799	        for (var key in attrs) {
    800	          if (attrs[key] !== model.get(key)) return false;
    801	        }
    802	        return true;
    803	      });
    804	    },
    805	
    806	    // Return the first model with matching attributes. Useful for simple cases
    807	    // of `find`.
    808	    findWhere: function(attrs) {
    809	      return this.where(attrs, true);
    810	    },
    811	
    812	    // Force the collection to re-sort itself. You don't need to call this under
    813	    // normal circumstances, as the set will maintain sort order as each item
    814	    // is added.
    815	    sort: function(options) {
    816	      if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
    817	      options || (options = {});
    818	
    819	      // Run sort based on type of `comparator`.
    820	      if (_.isString(this.comparator) || this.comparator.length === 1) {
    821	        this.models = this.sortBy(this.comparator, this);
    822	      } else {
    823	        this.models.sort(_.bind(this.comparator, this));
    824	      }
    825	
    826	      if (!options.silent) this.trigger('sort', this, options);
    827	      return this;
    828	    },
    829	
    830	    // Figure out the smallest index at which a model should be inserted so as
    831	    // to maintain order.
    832	    sortedIndex: function(model, value, context) {
    833	      value || (value = this.comparator);
    834	      var iterator = _.isFunction(value) ? value : function(model) {
    835	        return model.get(value);
    836	      };
    837	      return _.sortedIndex(this.models, model, iterator, context);
    838	    },
    839	
    840	    // Pluck an attribute from each model in the collection.
    841	    pluck: function(attr) {
    842	      return _.invoke(this.models, 'get', attr);
    843	    },
    844	
    845	    // Fetch the default set of models for this collection, resetting the
    846	    // collection when they arrive. If `reset: true` is passed, the response
    847	    // data will be passed through the `reset` method instead of `set`.
    848	    fetch: function(options) {
    849	      options = options ? _.clone(options) : {};
    850	      if (options.parse === void 0) options.parse = true;
    851	      var success = options.success;
    852	      var collection = this;
    853	      options.success = function(resp) {
    854	        var method = options.reset ? 'reset' : 'set';
    855	        collection[method](resp, options);
    856	        if (success) success(collection, resp, options);
    857	        collection.trigger('sync', collection, resp, options);
    858	      };
    859	      wrapError(this, options);
    860	      return this.sync('read', this, options);
    861	    },
    862	
    863	    // Create a new instance of a model in this collection. Add the model to the
    864	    // collection immediately, unless `wait: true` is passed, in which case we
    865	    // wait for the server to agree.
    866	    create: function(model, options) {
    867	      options = options ? _.clone(options) : {};
    868	      if (!(model = this._prepareModel(model, options))) return false;
    869	      if (!options.wait) this.add(model, options);
    870	      var collection = this;
    871	      var success = options.success;
    872	      options.success = function(resp) {
    873	        if (options.wait) collection.add(model, options);
    874	        if (success) success(model, resp, options);
    875	      };
    876	      model.save(null, options);
    877	      return model;
    878	    },
    879	
    880	    // **parse** converts a response into a list of models to be added to the
    881	    // collection. The default implementation is just to pass it through.
    882	    parse: function(resp, options) {
    883	      return resp;
    884	    },
    885	
    886	    // Create a new collection with an identical list of models as this one.
    887	    clone: function() {
    888	      return new this.constructor(this.models);
    889	    },
    890	
    891	    // Private method to reset all internal state. Called when the collection
    892	    // is first initialized or reset.
    893	    _reset: function() {
    894	      this.length = 0;
    895	      this.models = [];
    896	      this._byId  = {};
    897	    },
    898	
    899	    // Prepare a hash of attributes (or other model) to be added to this
    900	    // collection.
    901	    _prepareModel: function(attrs, options) {
    902	      if (attrs instanceof Model) {
    903	        if (!attrs.collection) attrs.collection = this;
    904	        return attrs;
    905	      }
    906	      options || (options = {});
    907	      options.collection = this;
    908	      var model = new this.model(attrs, options);
    909	      if (!model._validate(attrs, options)) {
    910	        this.trigger('invalid', this, attrs, options);
    911	        return false;
    912	      }
    913	      return model;
    914	    },
    915	
    916	    // Internal method to sever a model's ties to a collection.
    917	    _removeReference: function(model) {
    918	      if (this === model.collection) delete model.collection;
    919	      model.off('all', this._onModelEvent, this);
    920	    },
    921	
    922	    // Internal method called every time a model in the set fires an event.
    923	    // Sets need to update their indexes when models change ids. All other
    924	    // events simply proxy through. "add" and "remove" events that originate
    925	    // in other collections are ignored.
    926	    _onModelEvent: function(event, model, collection, options) {
    927	      if ((event === 'add' || event === 'remove') && collection !== this) return;
    928	      if (event === 'destroy') this.remove(model, options);
    929	      if (model && event === 'change:' + model.idAttribute) {
    930	        delete this._byId[model.previous(model.idAttribute)];
    931	        if (model.id != null) this._byId[model.id] = model;
    932	      }
    933	      this.trigger.apply(this, arguments);
    934	    }
    935	
    936	  });
    937	
    938	  // Underscore methods that we want to implement on the Collection.
    939	  // 90% of the core usefulness of Backbone Collections is actually implemented
    940	  // right here:
    941	  var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
    942	    'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
    943	    'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
    944	    'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
    945	    'tail', 'drop', 'last', 'without', 'indexOf', 'shuffle', 'lastIndexOf',
    946	    'isEmpty', 'chain'];
    947	
    948	  // Mix in each Underscore method as a proxy to `Collection#models`.
    949	  _.each(methods, function(method) {
    950	    Collection.prototype[method] = function() {
    951	      var args = slice.call(arguments);
    952	      args.unshift(this.models);
    953	      return _[method].apply(_, args);
    954	    };
    955	  });
    956	
    957	  // Underscore methods that take a property name as an argument.
    958	  var attributeMethods = ['groupBy', 'countBy', 'sortBy'];
    959	
    960	  // Use attributes instead of properties.
    961	  _.each(attributeMethods, function(method) {
    962	    Collection.prototype[method] = function(value, context) {
    963	      var iterator = _.isFunction(value) ? value : function(model) {
    964	        return model.get(value);
    965	      };
    966	      return _[method](this.models, iterator, context);
    967	    };
    968	  });
    969	
    970	  // Backbone.View
    971	  // -------------
    972	
    973	  // Backbone Views are almost more convention than they are actual code. A View
    974	  // is simply a JavaScript object that represents a logical chunk of UI in the
    975	  // DOM. This might be a single item, an entire list, a sidebar or panel, or
    976	  // even the surrounding frame which wraps your whole app. Defining a chunk of
    977	  // UI as a **View** allows you to define your DOM events declaratively, without
    978	  // having to worry about render order ... and makes it easy for the view to
    979	  // react to specific changes in the state of your models.
    980	
    981	  // Creating a Backbone.View creates its initial element outside of the DOM,
    982	  // if an existing element is not provided...
    983	  var View = Backbone.View = function(options) {
    984	    this.cid = _.uniqueId('view');
    985	    this._configure(options || {});
    986	    this._ensureElement();
    987	    this.initialize.apply(this, arguments);
    988	    this.delegateEvents();
    989	  };
    990	
    991	  // Cached regex to split keys for `delegate`.
    992	  var delegateEventSplitter = /^(\S+)\s*(.*)$/;
    993	
    994	  // List of view options to be merged as properties.
    995	  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
    996	
    997	  // Set up all inheritable **Backbone.View** properties and methods.
    998	  _.extend(View.prototype, Events, {
    999	
    1000	    // The default `tagName` of a View's element is `"div"`.
    1001	    tagName: 'div',
    1002	
    1003	    // jQuery delegate for element lookup, scoped to DOM elements within the
    1004	    // current view. This should be prefered to global lookups where possible.
    1005	    $: function(selector) {
    1006	      return this.$el.find(selector);
    1007	    },
    1008	
    1009	    // Initialize is an empty function by default. Override it with your own
    1010	    // initialization logic.
    1011	    initialize: function(){},
    1012	
    1013	    // **render** is the core function that your view should override, in order
    1014	    // to populate its element (`this.el`), with the appropriate HTML. The
    1015	    // convention is for **render** to always return `this`.
    1016	    render: function() {
    1017	      return this;
    1018	    },
    1019	
    1020	    // Remove this view by taking the element out of the DOM, and removing any
    1021	    // applicable Backbone.Events listeners.
    1022	    remove: function() {
    1023	      this.$el.remove();
    1024	      this.stopListening();
    1025	      return this;
    1026	    },
    1027	
    1028	    // Change the view's element (`this.el` property), including event
    1029	    // re-delegation.
    1030	    setElement: function(element, delegate) {
    1031	      if (this.$el) this.undelegateEvents();
    1032	      this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
    1033	      this.el = this.$el[0];
    1034	      if (delegate !== false) this.delegateEvents();
    1035	      return this;
    1036	    },
    1037	
    1038	    // Set callbacks, where `this.events` is a hash of
    1039	    //
    1040	    // *{"event selector": "callback"}*
    1041	    //
    1042	    //     {
    1043	    //       'mousedown .title':  'edit',
    1044	    //       'click .button':     'save'
    1045	    //       'click .open':       function(e) { ... }
    1046	    //     }
    1047	    //
    1048	    // pairs. Callbacks will be bound to the view, with `this` set properly.
    1049	    // Uses event delegation for efficiency.
    1050	    // Omitting the selector binds the event to `this.el`.
    1051	    // This only works for delegate-able events: not `focus`, `blur`, and
    1052	    // not `change`, `submit`, and `reset` in Internet Explorer.
    1053	    delegateEvents: function(events) {
    1054	      if (!(events || (events = _.result(this, 'events')))) return this;
    1055	      this.undelegateEvents();
    1056	      for (var key in events) {
    1057	        var method = events[key];
    1058	        if (!_.isFunction(method)) method = this[events[key]];
    1059	        if (!method) continue;
    1060	
    1061	        var match = key.match(delegateEventSplitter);
    1062	        var eventName = match[1], selector = match[2];
    1063	        method = _.bind(method, this);
    1064	        eventName += '.delegateEvents' + this.cid;
    1065	        if (selector === '') {
    1066	          this.$el.on(eventName, method);
    1067	        } else {
    1068	          this.$el.on(eventName, selector, method);
    1069	        }
    1070	      }
    1071	      return this;
    1072	    },
    1073	
    1074	    // Clears all callbacks previously bound to the view with `delegateEvents`.
    1075	    // You usually don't need to use this, but may wish to if you have multiple
    1076	    // Backbone views attached to the same DOM element.
    1077	    undelegateEvents: function() {
    1078	      this.$el.off('.delegateEvents' + this.cid);
    1079	      return this;
    1080	    },
    1081	
    1082	    // Performs the initial configuration of a View with a set of options.
    1083	    // Keys with special meaning *(e.g. model, collection, id, className)* are
    1084	    // attached directly to the view.  See `viewOptions` for an exhaustive
    1085	    // list.
    1086	    _configure: function(options) {
    1087	      if (this.options) options = _.extend({}, _.result(this, 'options'), options);
    1088	      _.extend(this, _.pick(options, viewOptions));
    1089	      this.options = options;
    1090	    },
    1091	
    1092	    // Ensure that the View has a DOM element to render into.
    1093	    // If `this.el` is a string, pass it through `$()`, take the first
    1094	    // matching element, and re-assign it to `el`. Otherwise, create
    1095	    // an element from the `id`, `className` and `tagName` properties.
    1096	    _ensureElement: function() {
    1097	      if (!this.el) {
    1098	        var attrs = _.extend({}, _.result(this, 'attributes'));
    1099	        if (this.id) attrs.id = _.result(this, 'id');
    1100	        if (this.className) attrs['class'] = _.result(this, 'className');
    1101	        var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
    1102	        this.setElement($el, false);
    1103	      } else {
    1104	        this.setElement(_.result(this, 'el'), false);
    1105	      }
    1106	    }
    1107	
    1108	  });
    1109	
    1110	  // Backbone.sync
    1111	  // -------------
    1112	
    1113	  // Override this function to change the manner in which Backbone persists
    1114	  // models to the server. You will be passed the type of request, and the
    1115	  // model in question. By default, makes a RESTful Ajax request
    1116	  // to the model's `url()`. Some possible customizations could be:
    1117	  //
    1118	  // * Use `setTimeout` to batch rapid-fire updates into a single request.
    1119	  // * Send up the models as XML instead of JSON.
    1120	  // * Persist models via WebSockets instead of Ajax.
    1121	  //
    1122	  // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
    1123	  // as `POST`, with a `_method` parameter containing the true HTTP method,
    1124	  // as well as all requests with the body as `application/x-www-form-urlencoded`
    1125	  // instead of `application/json` with the model in a param named `model`.
    1126	  // Useful when interfacing with server-side languages like **PHP** that make
    1127	  // it difficult to read the body of `PUT` requests.
    1128	  Backbone.sync = function(method, model, options) {
    1129	    var type = methodMap[method];
    1130	
    1131	    // Default options, unless specified.
    1132	    _.defaults(options || (options = {}), {
    1133	      emulateHTTP: Backbone.emulateHTTP,
    1134	      emulateJSON: Backbone.emulateJSON
    1135	    });
    1136	
    1137	    // Default JSON-request options.
    1138	    var params = {type: type, dataType: 'json'};
    1139	
    1140	    // Ensure that we have a URL.
    1141	    if (!options.url) {
    1142	      params.url = _.result(model, 'url') || urlError();
    1143	    }
    1144	
    1145	    // Ensure that we have the appropriate request data.
    1146	    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
    1147	      params.contentType = 'application/json';
    1148	      params.data = JSON.stringify(options.attrs || model.toJSON(options));
    1149	    }
    1150	
    1151	    // For older servers, emulate JSON by encoding the request into an HTML-form.
    1152	    if (options.emulateJSON) {
    1153	      params.contentType = 'application/x-www-form-urlencoded';
    1154	      params.data = params.data ? {model: params.data} : {};
    1155	    }
    1156	
    1157	    // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
    1158	    // And an `X-HTTP-Method-Override` header.
    1159	    if (options.emulateHTTP && (type === 'PUT' || type === 'DELETE' || type === 'PATCH')) {
    1160	      params.type = 'POST';
    1161	      if (options.emulateJSON) params.data._method = type;
    1162	      var beforeSend = options.beforeSend;
    1163	      options.beforeSend = function(xhr) {
    1164	        xhr.setRequestHeader('X-HTTP-Method-Override', type);
    1165	        if (beforeSend) return beforeSend.apply(this, arguments);
    1166	      };
    1167	    }
    1168	
    1169	    // Don't process data on a non-GET request.
    1170	    if (params.type !== 'GET' && !options.emulateJSON) {
    1171	      params.processData = false;
    1172	    }
    1173	
    1174	    // If we're sending a `PATCH` request, and we're in an old Internet Explorer
    1175	    // that still has ActiveX enabled by default, override jQuery to use that
    1176	    // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
    1177	    if (params.type === 'PATCH' && window.ActiveXObject &&
    1178	          !(window.external && window.external.msActiveXFilteringEnabled)) {
    1179	      params.xhr = function() {
    1180	        return new ActiveXObject("Microsoft.XMLHTTP");
    1181	      };
    1182	    }
    1183	
    1184	    // Make the request, allowing the user to override any Ajax options.
    1185	    var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
    1186	    model.trigger('request', model, xhr, options);
    1187	    return xhr;
    1188	  };
    1189	
    1190	  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
    1191	  var methodMap = {
    1192	    'create': 'POST',
    1193	    'update': 'PUT',
    1194	    'patch':  'PATCH',
    1195	    'delete': 'DELETE',
    1196	    'read':   'GET'
    1197	  };
    1198	
    1199	  // Set the default implementation of `Backbone.ajax` to proxy through to `$`.
    1200	  // Override this if you'd like to use a different library.
    1201	  Backbone.ajax = function() {
    1202	    return Backbone.$.ajax.apply(Backbone.$, arguments);
    1203	  };
    1204	
    1205	  // Backbone.Router
    1206	  // ---------------
    1207	
    1208	  // Routers map faux-URLs to actions, and fire events when routes are
    1209	  // matched. Creating a new one sets its `routes` hash, if not set statically.
    1210	  var Router = Backbone.Router = function(options) {
    1211	    options || (options = {});
    1212	    if (options.routes) this.routes = options.routes;
    1213	    this._bindRoutes();
    1214	    this.initialize.apply(this, arguments);
    1215	  };
    1216	
    1217	  // Cached regular expressions for matching named param parts and splatted
    1218	  // parts of route strings.
    1219	  var optionalParam = /\((.*?)\)/g;
    1220	  var namedParam    = /(\(\?)?:\w+/g;
    1221	  var splatParam    = /\*\w+/g;
    1222	  var escapeRegExp  = /[\-{}\[\]+?.,\\\^$|#\s]/g;
    1223	
    1224	  // Set up all inheritable **Backbone.Router** properties and methods.
    1225	  _.extend(Router.prototype, Events, {
    1226	
    1227	    // Initialize is an empty function by default. Override it with your own
    1228	    // initialization logic.
    1229	    initialize: function(){},
    1230	
    1231	    // Manually bind a single named route to a callback. For example:
    1232	    //
    1233	    //     this.route('search/:query/p:num', 'search', function(query, num) {
    1234	    //       ...
    1235	    //     });
    1236	    //
    1237	    route: function(route, name, callback) {
    1238	      if (!_.isRegExp(route)) route = this._routeToRegExp(route);
    1239	      if (_.isFunction(name)) {
    1240	        callback = name;
    1241	        name = '';
    1242	      }
    1243	      if (!callback) callback = this[name];
    1244	      var router = this;
    1245	      Backbone.history.route(route, function(fragment) {
    1246	        var args = router._extractParameters(route, fragment);
    1247	        callback && callback.apply(router, args);
    1248	        router.trigger.apply(router, ['route:' + name].concat(args));
    1249	        router.trigger('route', name, args);
    1250	        Backbone.history.trigger('route', router, name, args);
    1251	      });
    1252	      return this;
    1253	    },
    1254	
    1255	    // Simple proxy to `Backbone.history` to save a fragment into the history.
    1256	    navigate: function(fragment, options) {
    1257	      Backbone.history.navigate(fragment, options);
    1258	      return this;
    1259	    },
    1260	
    1261	    // Bind all defined routes to `Backbone.history`. We have to reverse the
    1262	    // order of the routes here to support behavior where the most general
    1263	    // routes can be defined at the bottom of the route map.
    1264	    _bindRoutes: function() {
    1265	      if (!this.routes) return;
    1266	      this.routes = _.result(this, 'routes');
    1267	      var route, routes = _.keys(this.routes);
    1268	      while ((route = routes.pop()) != null) {
    1269	        this.route(route, this.routes[route]);
    1270	      }
    1271	    },
    1272	
    1273	    // Convert a route string into a regular expression, suitable for matching
    1274	    // against the current location hash.
    1275	    _routeToRegExp: function(route) {
    1276	      route = route.replace(escapeRegExp, '\\$&')
    1277	                   .replace(optionalParam, '(?:$1)?')
    1278	                   .replace(namedParam, function(match, optional){
    1279	                     return optional ? match : '([^\/]+)';
    1280	                   })
    1281	                   .replace(splatParam, '(.*?)');
    1282	      return new RegExp('^' + route + '$');
    1283	    },
    1284	
    1285	    // Given a route, and a URL fragment that it matches, return the array of
    1286	    // extracted decoded parameters. Empty or unmatched parameters will be
    1287	    // treated as `null` to normalize cross-browser behavior.
    1288	    _extractParameters: function(route, fragment) {
    1289	      var params = route.exec(fragment).slice(1);
    1290	      return _.map(params, function(param) {
    1291	        return param ? decodeURIComponent(param) : null;
    1292	      });
    1293	    }
    1294	
    1295	  });
    1296	
    1297	  // Backbone.History
    1298	  // ----------------
    1299	
    1300	  // Handles cross-browser history management, based on either
    1301	  // [pushState](http://diveintohtml5.info/history.html) and real URLs, or
    1302	  // [onhashchange](https://developer.mozilla.org/en-US/docs/DOM/window.onhashchange)
    1303	  // and URL fragments. If the browser supports neither (old IE, natch),
    1304	  // falls back to polling.
    1305	  var History = Backbone.History = function() {
    1306	    this.handlers = [];
    1307	    _.bindAll(this, 'checkUrl');
    1308	
    1309	    // Ensure that `History` can be used outside of the browser.
    1310	    if (typeof window !== 'undefined') {
    1311	      this.location = window.location;
    1312	      this.history = window.history;
    1313	    }
    1314	  };
    1315	
    1316	  // Cached regex for stripping a leading hash/slash and trailing space.
    1317	  var routeStripper = /^[#\/]|\s+$/g;
    1318	
    1319	  // Cached regex for stripping leading and trailing slashes.
    1320	  var rootStripper = /^\/+|\/+$/g;
    1321	
    1322	  // Cached regex for detecting MSIE.
    1323	  var isExplorer = /msie [\w.]+/;
    1324	
    1325	  // Cached regex for removing a trailing slash.
    1326	  var trailingSlash = /\/$/;
    1327	
    1328	  // Has the history handling already been started?
    1329	  History.started = false;
    1330	
    1331	  // Set up all inheritable **Backbone.History** properties and methods.
    1332	  _.extend(History.prototype, Events, {
    1333	
    1334	    // The default interval to poll for hash changes, if necessary, is
    1335	    // twenty times a second.
    1336	    interval: 50,
    1337	
    1338	    // Gets the true hash value. Cannot use location.hash directly due to bug
    1339	    // in Firefox where location.hash will always be decoded.
    1340	    getHash: function(window) {
    1341	      var match = (window || this).location.href.match(/#(.*)$/);
    1342	      return match ? match[1] : '';
    1343	    },
    1344	
    1345	    // Get the cross-browser normalized URL fragment, either from the URL,
    1346	    // the hash, or the override.
    1347	    getFragment: function(fragment, forcePushState) {
    1348	      if (fragment == null) {
    1349	        if (this._hasPushState || !this._wantsHashChange || forcePushState) {
    1350	          fragment = this.location.pathname;
    1351	          var root = this.root.replace(trailingSlash, '');
    1352	          if (!fragment.indexOf(root)) fragment = fragment.substr(root.length);
    1353	        } else {
    1354	          fragment = this.getHash();
    1355	        }
    1356	      }
    1357	      return fragment.replace(routeStripper, '');
    1358	    },
    1359	
    1360	    // Start the hash change handling, returning `true` if the current URL matches
    1361	    // an existing route, and `false` otherwise.
    1362	    start: function(options) {
    1363	      if (History.started) throw new Error("Backbone.history has already been started");
    1364	      History.started = true;
    1365	
    1366	      // Figure out the initial configuration. Do we need an iframe?
    1367	      // Is pushState desired ... is it available?
    1368	      this.options          = _.extend({}, {root: '/'}, this.options, options);
    1369	      this.root             = this.options.root;
    1370	      this._wantsHashChange = this.options.hashChange !== false;
    1371	      this._wantsPushState  = !!this.options.pushState;
    1372	      this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
    1373	      var fragment          = this.getFragment();
    1374	      var docMode           = document.documentMode;
    1375	      var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
    1376	
    1377	      // Normalize root to always include a leading and trailing slash.
    1378	      this.root = ('/' + this.root + '/').replace(rootStripper, '/');
    1379	
    1380	      if (oldIE && this._wantsHashChange) {
    1381	        this.iframe = Backbone.$('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
    1382	        this.navigate(fragment);
    1383	      }
    1384	
    1385	      // Depending on whether we're using pushState or hashes, and whether
    1386	      // 'onhashchange' is supported, determine how we check the URL state.
    1387	      if (this._hasPushState) {
    1388	        Backbone.$(window).on('popstate', this.checkUrl);
    1389	      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
    1390	        Backbone.$(window).on('hashchange', this.checkUrl);
    1391	      } else if (this._wantsHashChange) {
    1392	        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
    1393	      }
    1394	
    1395	      // Determine if we need to change the base url, for a pushState link
    1396	      // opened by a non-pushState browser.
    1397	      this.fragment = fragment;
    1398	      var loc = this.location;
    1399	      var atRoot = loc.pathname.replace(/[^\/]$/, '$&/') === this.root;
    1400	
    1401	      // If we've started off with a route from a `pushState`-enabled browser,
    1402	      // but we're currently in a browser that doesn't support it...
    1403	      if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
    1404	        this.fragment = this.getFragment(null, true);
    1405	        this.location.replace(this.root + this.location.search + '#' + this.fragment);
    1406	        // Return immediately as browser will do redirect to new url
    1407	        return true;
    1408	
    1409	      // Or if we've started out with a hash-based route, but we're currently
    1410	      // in a browser where it could be `pushState`-based instead...
    1411	      } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
    1412	        this.fragment = this.getHash().replace(routeStripper, '');
    1413	        this.history.replaceState({}, document.title, this.root + this.fragment + loc.search);
    1414	      }
    1415	
    1416	      if (!this.options.silent) return this.loadUrl();
    1417	    },
    1418	
    1419	    // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
    1420	    // but possibly useful for unit testing Routers.
    1421	    stop: function() {
    1422	      Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
    1423	      clearInterval(this._checkUrlInterval);
    1424	      History.started = false;
    1425	    },
    1426	
    1427	    // Add a route to be tested when the fragment changes. Routes added later
    1428	    // may override previous routes.
    1429	    route: function(route, callback) {
    1430	      this.handlers.unshift({route: route, callback: callback});
    1431	    },
    1432	
    1433	    // Checks the current URL to see if it has changed, and if it has,
    1434	    // calls `loadUrl`, normalizing across the hidden iframe.
    1435	    checkUrl: function(e) {
    1436	      var current = this.getFragment();
    1437	      if (current === this.fragment && this.iframe) {
    1438	        current = this.getFragment(this.getHash(this.iframe));
    1439	      }
    1440	      if (current === this.fragment) return false;
    1441	      if (this.iframe) this.navigate(current);
    1442	      this.loadUrl() || this.loadUrl(this.getHash());
    1443	    },
    1444	
    1445	    // Attempt to load the current URL fragment. If a route succeeds with a
    1446	    // match, returns `true`. If no defined routes matches the fragment,
    1447	    // returns `false`.
    1448	    loadUrl: function(fragmentOverride) {
    1449	      var fragment = this.fragment = this.getFragment(fragmentOverride);
    1450	      var matched = _.any(this.handlers, function(handler) {
    1451	        if (handler.route.test(fragment)) {
    1452	          handler.callback(fragment);
    1453	          return true;
    1454	        }
    1455	      });
    1456	      return matched;
    1457	    },
    1458	
    1459	    // Save a fragment into the hash history, or replace the URL state if the
    1460	    // 'replace' option is passed. You are responsible for properly URL-encoding
    1461	    // the fragment in advance.
    1462	    //
    1463	    // The options object can contain `trigger: true` if you wish to have the
    1464	    // route callback be fired (not usually desirable), or `replace: true`, if
    1465	    // you wish to modify the current URL without adding an entry to the history.
    1466	    navigate: function(fragment, options) {
    1467	      if (!History.started) return false;
    1468	      if (!options || options === true) options = {trigger: options};
    1469	      fragment = this.getFragment(fragment || '');
    1470	      if (this.fragment === fragment) return;
    1471	      this.fragment = fragment;
    1472	      var url = this.root + fragment;
    1473	
    1474	      // If pushState is available, we use it to set the fragment as a real URL.
    1475	      if (this._hasPushState) {
    1476	        this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
    1477	
    1478	      // If hash changes haven't been explicitly disabled, update the hash
    1479	      // fragment to store history.
    1480	      } else if (this._wantsHashChange) {
    1481	        this._updateHash(this.location, fragment, options.replace);
    1482	        if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
    1483	          // Opening and closing the iframe tricks IE7 and earlier to push a
    1484	          // history entry on hash-tag change.  When replace is true, we don't
    1485	          // want this.
    1486	          if(!options.replace) this.iframe.document.open().close();
    1487	          this._updateHash(this.iframe.location, fragment, options.replace);
    1488	        }
    1489	
    1490	      // If you've told us that you explicitly don't want fallback hashchange-
    1491	      // based history, then `navigate` becomes a page refresh.
    1492	      } else {
    1493	        return this.location.assign(url);
    1494	      }
    1495	      if (options.trigger) this.loadUrl(fragment);
    1496	    },
    1497	
    1498	    // Update the hash location, either replacing the current entry, or adding
    1499	    // a new one to the browser history.
    1500	    _updateHash: function(location, fragment, replace) {
    1501	      if (replace) {
    1502	        var href = location.href.replace(/(javascript:|#).*$/, '');
    1503	        location.replace(href + '#' + fragment);
    1504	      } else {
    1505	        // Some browsers require that `hash` contains a leading #.
    1506	        location.hash = '#' + fragment;
    1507	      }
    1508	    }
    1509	
    1510	  });
    1511	
    1512	  // Create the default Backbone.history.
    1513	  Backbone.history = new History;
    1514	
    1515	  // Helpers
    1516	  // -------
    1517	
    1518	  // Helper function to correctly set up the prototype chain, for subclasses.
    1519	  // Similar to `goog.inherits`, but uses a hash of prototype properties and
    1520	  // class properties to be extended.
    1521	  var extend = function(protoProps, staticProps) {
    1522	    var parent = this;
    1523	    var child;
    1524	
    1525	    // The constructor function for the new subclass is either defined by you
    1526	    // (the "constructor" property in your `extend` definition), or defaulted
    1527	    // by us to simply call the parent's constructor.
    1528	    if (protoProps && _.has(protoProps, 'constructor')) {
    1529	      child = protoProps.constructor;
    1530	    } else {
    1531	      child = function(){ return parent.apply(this, arguments); };
    1532	    }
    1533	
    1534	    // Add static properties to the constructor function, if supplied.
    1535	    _.extend(child, parent, staticProps);
    1536	
    1537	    // Set the prototype chain to inherit from `parent`, without calling
    1538	    // `parent`'s constructor function.
    1539	    var Surrogate = function(){ this.constructor = child; };
    1540	    Surrogate.prototype = parent.prototype;
    1541	    child.prototype = new Surrogate;
    1542	
    1543	    // Add prototype properties (instance properties) to the subclass,
    1544	    // if supplied.
    1545	    if (protoProps) _.extend(child.prototype, protoProps);
    1546	
    1547	    // Set a convenience property in case the parent's prototype is needed
    1548	    // later.
    1549	    child.__super__ = parent.prototype;
    1550	
    1551	    return child;
    1552	  };
    1553	
    1554	  // Set up inheritance for the model, collection, router, view and history.
    1555	  Model.extend = Collection.extend = Router.extend = View.extend = History.extend = extend;
    1556	
    1557	  // Throw an error when a URL is needed, and none is supplied.
    1558	  var urlError = function() {
    1559	    throw new Error('A "url" property or function must be specified');
    1560	  };
    1561	
    1562	  // Wrap an optional error callback with a fallback error event.
    1563	  var wrapError = function (model, options) {
    1564	    var error = options.error;
    1565	    options.error = function(resp) {
    1566	      if (error) error(model, resp, options);
    1567	      model.trigger('error', model, resp, options);
    1568	    };
    1569	  };
    1570	
    1571	}).call(this);
  • WordPress 源代码——主干(backbone-0.9.2.js)

    WordPress 源代码——主干(backbone-0.9.2.js)

    //     Backbone.js 0.9.2
    2	
    3	//     (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
    4	//     Backbone may be freely distributed under the MIT license.
    5	//     For all details and documentation:
    6	//     http://backbonejs.org
    7	
    8	(function(){
    9	
    10	  // Initial Setup
    11	  // -------------
    12	
    13	  // Save a reference to the global object (`window` in the browser, `global`
    14	  // on the server).
    15	  var root = this;
    16	
    17	  // Save the previous value of the `Backbone` variable, so that it can be
    18	  // restored later on, if `noConflict` is used.
    19	  var previousBackbone = root.Backbone;
    20	
    21	  // Create a local reference to slice/splice.
    22	  var slice = Array.prototype.slice;
    23	  var splice = Array.prototype.splice;
    24	
    25	  // The top-level namespace. All public Backbone classes and modules will
    26	  // be attached to this. Exported for both CommonJS and the browser.
    27	  var Backbone;
    28	  if (typeof exports !== 'undefined') {
    29	    Backbone = exports;
    30	  } else {
    31	    Backbone = root.Backbone = {};
    32	  }
    33	
    34	  // Current version of the library. Keep in sync with `package.json`.
    35	  Backbone.VERSION = '0.9.2';
    36	
    37	  // Require Underscore, if we're on the server, and it's not already present.
    38	  var _ = root._;
    39	  if (!_ && (typeof require !== 'undefined')) _ = require('underscore');
    40	
    41	  // For Backbone's purposes, jQuery, Zepto, or Ender owns the `$` variable.
    42	  var $ = root.jQuery || root.Zepto || root.ender;
    43	
    44	  // Set the JavaScript library that will be used for DOM manipulation and
    45	  // Ajax calls (a.k.a. the `$` variable). By default Backbone will use: jQuery,
    46	  // Zepto, or Ender; but the `setDomLibrary()` method lets you inject an
    47	  // alternate JavaScript library (or a mock library for testing your views
    48	  // outside of a browser).
    49	  Backbone.setDomLibrary = function(lib) {
    50	    $ = lib;
    51	  };
    52	
    53	  // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
    54	  // to its previous owner. Returns a reference to this Backbone object.
    55	  Backbone.noConflict = function() {
    56	    root.Backbone = previousBackbone;
    57	    return this;
    58	  };
    59	
    60	  // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
    61	  // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
    62	  // set a `X-Http-Method-Override` header.
    63	  Backbone.emulateHTTP = false;
    64	
    65	  // Turn on `emulateJSON` to support legacy servers that can't deal with direct
    66	  // `application/json` requests ... will encode the body as
    67	  // `application/x-www-form-urlencoded` instead and will send the model in a
    68	  // form param named `model`.
    69	  Backbone.emulateJSON = false;
    70	
    71	  // Backbone.Events
    72	  // -----------------
    73	
    74	  // Regular expression used to split event strings
    75	  var eventSplitter = /\s+/;
    76	
    77	  // A module that can be mixed in to *any object* in order to provide it with
    78	  // custom events. You may bind with `on` or remove with `off` callback functions
    79	  // to an event; trigger`-ing an event fires all callbacks in succession.
    80	  //
    81	  //     var object = {};
    82	  //     _.extend(object, Backbone.Events);
    83	  //     object.on('expand', function(){ alert('expanded'); });
    84	  //     object.trigger('expand');
    85	  //
    86	  var Events = Backbone.Events = {
    87	
    88	    // Bind one or more space separated events, `events`, to a `callback`
    89	    // function. Passing `"all"` will bind the callback to all events fired.
    90	    on: function(events, callback, context) {
    91	
    92	      var calls, event, node, tail, list;
    93	      if (!callback) return this;
    94	      events = events.split(eventSplitter);
    95	      calls = this._callbacks || (this._callbacks = {});
    96	
    97	      // Create an immutable callback list, allowing traversal during
    98	      // modification.  The tail is an empty object that will always be used
    99	      // as the next node.
    100	      while (event = events.shift()) {
    101	        list = calls[event];
    102	        node = list ? list.tail : {};
    103	        node.next = tail = {};
    104	        node.context = context;
    105	        node.callback = callback;
    106	        calls[event] = {tail: tail, next: list ? list.next : node};
    107	      }
    108	
    109	      return this;
    110	    },
    111	
    112	    // Remove one or many callbacks. If `context` is null, removes all callbacks
    113	    // with that function. If `callback` is null, removes all callbacks for the
    114	    // event. If `events` is null, removes all bound callbacks for all events.
    115	    off: function(events, callback, context) {
    116	      var event, calls, node, tail, cb, ctx;
    117	
    118	      // No events, or removing *all* events.
    119	      if (!(calls = this._callbacks)) return;
    120	      if (!(events || callback || context)) {
    121	        delete this._callbacks;
    122	        return this;
    123	      }
    124	
    125	      // Loop through the listed events and contexts, splicing them out of the
    126	      // linked list of callbacks if appropriate.
    127	      events = events ? events.split(eventSplitter) : _.keys(calls);
    128	      while (event = events.shift()) {
    129	        node = calls[event];
    130	        delete calls[event];
    131	        if (!node || !(callback || context)) continue;
    132	        // Create a new list, omitting the indicated callbacks.
    133	        tail = node.tail;
    134	        while ((node = node.next) !== tail) {
    135	          cb = node.callback;
    136	          ctx = node.context;
    137	          if ((callback && cb !== callback) || (context && ctx !== context)) {
    138	            this.on(event, cb, ctx);
    139	          }
    140	        }
    141	      }
    142	
    143	      return this;
    144	    },
    145	
    146	    // Trigger one or many events, firing all bound callbacks. Callbacks are
    147	    // passed the same arguments as `trigger` is, apart from the event name
    148	    // (unless you're listening on `"all"`, which will cause your callback to
    149	    // receive the true name of the event as the first argument).
    150	    trigger: function(events) {
    151	      var event, node, calls, tail, args, all, rest;
    152	      if (!(calls = this._callbacks)) return this;
    153	      all = calls.all;
    154	      events = events.split(eventSplitter);
    155	      rest = slice.call(arguments, 1);
    156	
    157	      // For each event, walk through the linked list of callbacks twice,
    158	      // first to trigger the event, then to trigger any `"all"` callbacks.
    159	      while (event = events.shift()) {
    160	        if (node = calls[event]) {
    161	          tail = node.tail;
    162	          while ((node = node.next) !== tail) {
    163	            node.callback.apply(node.context || this, rest);
    164	          }
    165	        }
    166	        if (node = all) {
    167	          tail = node.tail;
    168	          args = [event].concat(rest);
    169	          while ((node = node.next) !== tail) {
    170	            node.callback.apply(node.context || this, args);
    171	          }
    172	        }
    173	      }
    174	
    175	      return this;
    176	    }
    177	
    178	  };
    179	
    180	  // Aliases for backwards compatibility.
    181	  Events.bind   = Events.on;
    182	  Events.unbind = Events.off;
    183	
    184	  // Backbone.Model
    185	  // --------------
    186	
    187	  // Create a new model, with defined attributes. A client id (`cid`)
    188	  // is automatically generated and assigned for you.
    189	  var Model = Backbone.Model = function(attributes, options) {
    190	    var defaults;
    191	    attributes || (attributes = {});
    192	    if (options && options.parse) attributes = this.parse(attributes);
    193	    if (defaults = getValue(this, 'defaults')) {
    194	      attributes = _.extend({}, defaults, attributes);
    195	    }
    196	    if (options && options.collection) this.collection = options.collection;
    197	    this.attributes = {};
    198	    this._escapedAttributes = {};
    199	    this.cid = _.uniqueId('c');
    200	    this.changed = {};
    201	    this._silent = {};
    202	    this._pending = {};
    203	    this.set(attributes, {silent: true});
    204	    // Reset change tracking.
    205	    this.changed = {};
    206	    this._silent = {};
    207	    this._pending = {};
    208	    this._previousAttributes = _.clone(this.attributes);
    209	    this.initialize.apply(this, arguments);
    210	  };
    211	
    212	  // Attach all inheritable methods to the Model prototype.
    213	  _.extend(Model.prototype, Events, {
    214	
    215	    // A hash of attributes whose current and previous value differ.
    216	    changed: null,
    217	
    218	    // A hash of attributes that have silently changed since the last time
    219	    // `change` was called.  Will become pending attributes on the next call.
    220	    _silent: null,
    221	
    222	    // A hash of attributes that have changed since the last `'change'` event
    223	    // began.
    224	    _pending: null,
    225	
    226	    // The default name for the JSON `id` attribute is `"id"`. MongoDB and
    227	    // CouchDB users may want to set this to `"_id"`.
    228	    idAttribute: 'id',
    229	
    230	    // Initialize is an empty function by default. Override it with your own
    231	    // initialization logic.
    232	    initialize: function(){},
    233	
    234	    // Return a copy of the model's `attributes` object.
    235	    toJSON: function(options) {
    236	      return _.clone(this.attributes);
    237	    },
    238	
    239	    // Get the value of an attribute.
    240	    get: function(attr) {
    241	      return this.attributes[attr];
    242	    },
    243	
    244	    // Get the HTML-escaped value of an attribute.
    245	    escape: function(attr) {
    246	      var html;
    247	      if (html = this._escapedAttributes[attr]) return html;
    248	      var val = this.get(attr);
    249	      return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val);
    250	    },
    251	
    252	    // Returns `true` if the attribute contains a value that is not null
    253	    // or undefined.
    254	    has: function(attr) {
    255	      return this.get(attr) != null;
    256	    },
    257	
    258	    // Set a hash of model attributes on the object, firing `"change"` unless
    259	    // you choose to silence it.
    260	    set: function(key, value, options) {
    261	      var attrs, attr, val;
    262	
    263	      // Handle both `"key", value` and `{key: value}` -style arguments.
    264	      if (_.isObject(key) || key == null) {
    265	        attrs = key;
    266	        options = value;
    267	      } else {
    268	        attrs = {};
    269	        attrs[key] = value;
    270	      }
    271	
    272	      // Extract attributes and options.
    273	      options || (options = {});
    274	      if (!attrs) return this;
    275	      if (attrs instanceof Model) attrs = attrs.attributes;
    276	      if (options.unset) for (attr in attrs) attrs[attr] = void 0;
    277	
    278	      // Run validation.
    279	      if (!this._validate(attrs, options)) return false;
    280	
    281	      // Check for changes of `id`.
    282	      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
    283	
    284	      var changes = options.changes = {};
    285	      var now = this.attributes;
    286	      var escaped = this._escapedAttributes;
    287	      var prev = this._previousAttributes || {};
    288	
    289	      // For each `set` attribute...
    290	      for (attr in attrs) {
    291	        val = attrs[attr];
    292	
    293	        // If the new and current value differ, record the change.
    294	        if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
    295	          delete escaped[attr];
    296	          (options.silent ? this._silent : changes)[attr] = true;
    297	        }
    298	
    299	        // Update or delete the current value.
    300	        options.unset ? delete now[attr] : now[attr] = val;
    301	
    302	        // If the new and previous value differ, record the change.  If not,
    303	        // then remove changes for this attribute.
    304	        if (!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) {
    305	          this.changed[attr] = val;
    306	          if (!options.silent) this._pending[attr] = true;
    307	        } else {
    308	          delete this.changed[attr];
    309	          delete this._pending[attr];
    310	        }
    311	      }
    312	
    313	      // Fire the `"change"` events.
    314	      if (!options.silent) this.change(options);
    315	      return this;
    316	    },
    317	
    318	    // Remove an attribute from the model, firing `"change"` unless you choose
    319	    // to silence it. `unset` is a noop if the attribute doesn't exist.
    320	    unset: function(attr, options) {
    321	      (options || (options = {})).unset = true;
    322	      return this.set(attr, null, options);
    323	    },
    324	
    325	    // Clear all attributes on the model, firing `"change"` unless you choose
    326	    // to silence it.
    327	    clear: function(options) {
    328	      (options || (options = {})).unset = true;
    329	      return this.set(_.clone(this.attributes), options);
    330	    },
    331	
    332	    // Fetch the model from the server. If the server's representation of the
    333	    // model differs from its current attributes, they will be overriden,
    334	    // triggering a `"change"` event.
    335	    fetch: function(options) {
    336	      options = options ? _.clone(options) : {};
    337	      var model = this;
    338	      var success = options.success;
    339	      options.success = function(resp, status, xhr) {
    340	        if (!model.set(model.parse(resp, xhr), options)) return false;
    341	        if (success) success(model, resp);
    342	      };
    343	      options.error = Backbone.wrapError(options.error, model, options);
    344	      return (this.sync || Backbone.sync).call(this, 'read', this, options);
    345	    },
    346	
    347	    // Set a hash of model attributes, and sync the model to the server.
    348	    // If the server returns an attributes hash that differs, the model's
    349	    // state will be `set` again.
    350	    save: function(key, value, options) {
    351	      var attrs, current;
    352	
    353	      // Handle both `("key", value)` and `({key: value})` -style calls.
    354	      if (_.isObject(key) || key == null) {
    355	        attrs = key;
    356	        options = value;
    357	      } else {
    358	        attrs = {};
    359	        attrs[key] = value;
    360	      }
    361	      options = options ? _.clone(options) : {};
    362	
    363	      // If we're "wait"-ing to set changed attributes, validate early.
    364	      if (options.wait) {
    365	        if (!this._validate(attrs, options)) return false;
    366	        current = _.clone(this.attributes);
    367	      }
    368	
    369	      // Regular saves `set` attributes before persisting to the server.
    370	      var silentOptions = _.extend({}, options, {silent: true});
    371	      if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) {
    372	        return false;
    373	      }
    374	
    375	      // After a successful server-side save, the client is (optionally)
    376	      // updated with the server-side state.
    377	      var model = this;
    378	      var success = options.success;
    379	      options.success = function(resp, status, xhr) {
    380	        var serverAttrs = model.parse(resp, xhr);
    381	        if (options.wait) {
    382	          delete options.wait;
    383	          serverAttrs = _.extend(attrs || {}, serverAttrs);
    384	        }
    385	        if (!model.set(serverAttrs, options)) return false;
    386	        if (success) {
    387	          success(model, resp);
    388	        } else {
    389	          model.trigger('sync', model, resp, options);
    390	        }
    391	      };
    392	
    393	      // Finish configuring and sending the Ajax request.
    394	      options.error = Backbone.wrapError(options.error, model, options);
    395	      var method = this.isNew() ? 'create' : 'update';
    396	      var xhr = (this.sync || Backbone.sync).call(this, method, this, options);
    397	      if (options.wait) this.set(current, silentOptions);
    398	      return xhr;
    399	    },
    400	
    401	    // Destroy this model on the server if it was already persisted.
    402	    // Optimistically removes the model from its collection, if it has one.
    403	    // If `wait: true` is passed, waits for the server to respond before removal.
    404	    destroy: function(options) {
    405	      options = options ? _.clone(options) : {};
    406	      var model = this;
    407	      var success = options.success;
    408	
    409	      var triggerDestroy = function() {
    410	        model.trigger('destroy', model, model.collection, options);
    411	      };
    412	
    413	      if (this.isNew()) {
    414	        triggerDestroy();
    415	        return false;
    416	      }
    417	
    418	      options.success = function(resp) {
    419	        if (options.wait) triggerDestroy();
    420	        if (success) {
    421	          success(model, resp);
    422	        } else {
    423	          model.trigger('sync', model, resp, options);
    424	        }
    425	      };
    426	
    427	      options.error = Backbone.wrapError(options.error, model, options);
    428	      var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options);
    429	      if (!options.wait) triggerDestroy();
    430	      return xhr;
    431	    },
    432	
    433	    // Default URL for the model's representation on the server -- if you're
    434	    // using Backbone's restful methods, override this to change the endpoint
    435	    // that will be called.
    436	    url: function() {
    437	      var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError();
    438	      if (this.isNew()) return base;
    439	      return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
    440	    },
    441	
    442	    // **parse** converts a response into the hash of attributes to be `set` on
    443	    // the model. The default implementation is just to pass the response along.
    444	    parse: function(resp, xhr) {
    445	      return resp;
    446	    },
    447	
    448	    // Create a new model with identical attributes to this one.
    449	    clone: function() {
    450	      return new this.constructor(this.attributes);
    451	    },
    452	
    453	    // A model is new if it has never been saved to the server, and lacks an id.
    454	    isNew: function() {
    455	      return this.id == null;
    456	    },
    457	
    458	    // Call this method to manually fire a `"change"` event for this model and
    459	    // a `"change:attribute"` event for each changed attribute.
    460	    // Calling this will cause all objects observing the model to update.
    461	    change: function(options) {
    462	      options || (options = {});
    463	      var changing = this._changing;
    464	      this._changing = true;
    465	
    466	      // Silent changes become pending changes.
    467	      for (var attr in this._silent) this._pending[attr] = true;
    468	
    469	      // Silent changes are triggered.
    470	      var changes = _.extend({}, options.changes, this._silent);
    471	      this._silent = {};
    472	      for (var attr in changes) {
    473	        this.trigger('change:' + attr, this, this.get(attr), options);
    474	      }
    475	      if (changing) return this;
    476	
    477	      // Continue firing `"change"` events while there are pending changes.
    478	      while (!_.isEmpty(this._pending)) {
    479	        this._pending = {};
    480	        this.trigger('change', this, options);
    481	        // Pending and silent changes still remain.
    482	        for (var attr in this.changed) {
    483	          if (this._pending[attr] || this._silent[attr]) continue;
    484	          delete this.changed[attr];
    485	        }
    486	        this._previousAttributes = _.clone(this.attributes);
    487	      }
    488	
    489	      this._changing = false;
    490	      return this;
    491	    },
    492	
    493	    // Determine if the model has changed since the last `"change"` event.
    494	    // If you specify an attribute name, determine if that attribute has changed.
    495	    hasChanged: function(attr) {
    496	      if (!arguments.length) return !_.isEmpty(this.changed);
    497	      return _.has(this.changed, attr);
    498	    },
    499	
    500	    // Return an object containing all the attributes that have changed, or
    501	    // false if there are no changed attributes. Useful for determining what
    502	    // parts of a view need to be updated and/or what attributes need to be
    503	    // persisted to the server. Unset attributes will be set to undefined.
    504	    // You can also pass an attributes object to diff against the model,
    505	    // determining if there *would be* a change.
    506	    changedAttributes: function(diff) {
    507	      if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
    508	      var val, changed = false, old = this._previousAttributes;
    509	      for (var attr in diff) {
    510	        if (_.isEqual(old[attr], (val = diff[attr]))) continue;
    511	        (changed || (changed = {}))[attr] = val;
    512	      }
    513	      return changed;
    514	    },
    515	
    516	    // Get the previous value of an attribute, recorded at the time the last
    517	    // `"change"` event was fired.
    518	    previous: function(attr) {
    519	      if (!arguments.length || !this._previousAttributes) return null;
    520	      return this._previousAttributes[attr];
    521	    },
    522	
    523	    // Get all of the attributes of the model at the time of the previous
    524	    // `"change"` event.
    525	    previousAttributes: function() {
    526	      return _.clone(this._previousAttributes);
    527	    },
    528	
    529	    // Check if the model is currently in a valid state. It's only possible to
    530	    // get into an *invalid* state if you're using silent changes.
    531	    isValid: function() {
    532	      return !this.validate(this.attributes);
    533	    },
    534	
    535	    // Run validation against the next complete set of model attributes,
    536	    // returning `true` if all is well. If a specific `error` callback has
    537	    // been passed, call that instead of firing the general `"error"` event.
    538	    _validate: function(attrs, options) {
    539	      if (options.silent || !this.validate) return true;
    540	      attrs = _.extend({}, this.attributes, attrs);
    541	      var error = this.validate(attrs, options);
    542	      if (!error) return true;
    543	      if (options && options.error) {
    544	        options.error(this, error, options);
    545	      } else {
    546	        this.trigger('error', this, error, options);
    547	      }
    548	      return false;
    549	    }
    550	
    551	  });
    552	
    553	  // Backbone.Collection
    554	  // -------------------
    555	
    556	  // Provides a standard collection class for our sets of models, ordered
    557	  // or unordered. If a `comparator` is specified, the Collection will maintain
    558	  // its models in sort order, as they're added and removed.
    559	  var Collection = Backbone.Collection = function(models, options) {
    560	    options || (options = {});
    561	    if (options.model) this.model = options.model;
    562	    if (options.comparator) this.comparator = options.comparator;
    563	    this._reset();
    564	    this.initialize.apply(this, arguments);
    565	    if (models) this.reset(models, {silent: true, parse: options.parse});
    566	  };
    567	
    568	  // Define the Collection's inheritable methods.
    569	  _.extend(Collection.prototype, Events, {
    570	
    571	    // The default model for a collection is just a **Backbone.Model**.
    572	    // This should be overridden in most cases.
    573	    model: Model,
    574	
    575	    // Initialize is an empty function by default. Override it with your own
    576	    // initialization logic.
    577	    initialize: function(){},
    578	
    579	    // The JSON representation of a Collection is an array of the
    580	    // models' attributes.
    581	    toJSON: function(options) {
    582	      return this.map(function(model){ return model.toJSON(options); });
    583	    },
    584	
    585	    // Add a model, or list of models to the set. Pass **silent** to avoid
    586	    // firing the `add` event for every new model.
    587	    add: function(models, options) {
    588	      var i, index, length, model, cid, id, cids = {}, ids = {}, dups = [];
    589	      options || (options = {});
    590	      models = _.isArray(models) ? models.slice() : [models];
    591	
    592	      // Begin by turning bare objects into model references, and preventing
    593	      // invalid models or duplicate models from being added.
    594	      for (i = 0, length = models.length; i < length; i++) {
    595	        if (!(model = models[i] = this._prepareModel(models[i], options))) {
    596	          throw new Error("Can't add an invalid model to a collection");
    597	        }
    598	        cid = model.cid;
    599	        id = model.id;
    600	        if (cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) {
    601	          dups.push(i);
    602	          continue;
    603	        }
    604	        cids[cid] = ids[id] = model;
    605	      }
    606	
    607	      // Remove duplicates.
    608	      i = dups.length;
    609	      while (i--) {
    610	        models.splice(dups[i], 1);
    611	      }
    612	
    613	      // Listen to added models' events, and index models for lookup by
    614	      // `id` and by `cid`.
    615	      for (i = 0, length = models.length; i < length; i++) {
    616	        (model = models[i]).on('all', this._onModelEvent, this);
    617	        this._byCid[model.cid] = model;
    618	        if (model.id != null) this._byId[model.id] = model;
    619	      }
    620	
    621	      // Insert models into the collection, re-sorting if needed, and triggering
    622	      // `add` events unless silenced.
    623	      this.length += length;
    624	      index = options.at != null ? options.at : this.models.length;
    625	      splice.apply(this.models, [index, 0].concat(models));
    626	      if (this.comparator) this.sort({silent: true});
    627	      if (options.silent) return this;
    628	      for (i = 0, length = this.models.length; i < length; i++) {
    629	        if (!cids[(model = this.models[i]).cid]) continue;
    630	        options.index = i;
    631	        model.trigger('add', model, this, options);
    632	      }
    633	      return this;
    634	    },
    635	
    636	    // Remove a model, or a list of models from the set. Pass silent to avoid
    637	    // firing the `remove` event for every model removed.
    638	    remove: function(models, options) {
    639	      var i, l, index, model;
    640	      options || (options = {});
    641	      models = _.isArray(models) ? models.slice() : [models];
    642	      for (i = 0, l = models.length; i < l; i++) {
    643	        model = this.getByCid(models[i]) || this.get(models[i]);
    644	        if (!model) continue;
    645	        delete this._byId[model.id];
    646	        delete this._byCid[model.cid];
    647	        index = this.indexOf(model);
    648	        this.models.splice(index, 1);
    649	        this.length--;
    650	        if (!options.silent) {
    651	          options.index = index;
    652	          model.trigger('remove', model, this, options);
    653	        }
    654	        this._removeReference(model);
    655	      }
    656	      return this;
    657	    },
    658	
    659	    // Add a model to the end of the collection.
    660	    push: function(model, options) {
    661	      model = this._prepareModel(model, options);
    662	      this.add(model, options);
    663	      return model;
    664	    },
    665	
    666	    // Remove a model from the end of the collection.
    667	    pop: function(options) {
    668	      var model = this.at(this.length - 1);
    669	      this.remove(model, options);
    670	      return model;
    671	    },
    672	
    673	    // Add a model to the beginning of the collection.
    674	    unshift: function(model, options) {
    675	      model = this._prepareModel(model, options);
    676	      this.add(model, _.extend({at: 0}, options));
    677	      return model;
    678	    },
    679	
    680	    // Remove a model from the beginning of the collection.
    681	    shift: function(options) {
    682	      var model = this.at(0);
    683	      this.remove(model, options);
    684	      return model;
    685	    },
    686	
    687	    // Get a model from the set by id.
    688	    get: function(id) {
    689	      if (id == null) return void 0;
    690	      return this._byId[id.id != null ? id.id : id];
    691	    },
    692	
    693	    // Get a model from the set by client id.
    694	    getByCid: function(cid) {
    695	      return cid && this._byCid[cid.cid || cid];
    696	    },
    697	
    698	    // Get the model at the given index.
    699	    at: function(index) {
    700	      return this.models[index];
    701	    },
    702	
    703	    // Return models with matching attributes. Useful for simple cases of `filter`.
    704	    where: function(attrs) {
    705	      if (_.isEmpty(attrs)) return [];
    706	      return this.filter(function(model) {
    707	        for (var key in attrs) {
    708	          if (attrs[key] !== model.get(key)) return false;
    709	        }
    710	        return true;
    711	      });
    712	    },
    713	
    714	    // Force the collection to re-sort itself. You don't need to call this under
    715	    // normal circumstances, as the set will maintain sort order as each item
    716	    // is added.
    717	    sort: function(options) {
    718	      options || (options = {});
    719	      if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
    720	      var boundComparator = _.bind(this.comparator, this);
    721	      if (this.comparator.length == 1) {
    722	        this.models = this.sortBy(boundComparator);
    723	      } else {
    724	        this.models.sort(boundComparator);
    725	      }
    726	      if (!options.silent) this.trigger('reset', this, options);
    727	      return this;
    728	    },
    729	
    730	    // Pluck an attribute from each model in the collection.
    731	    pluck: function(attr) {
    732	      return _.map(this.models, function(model){ return model.get(attr); });
    733	    },
    734	
    735	    // When you have more items than you want to add or remove individually,
    736	    // you can reset the entire set with a new list of models, without firing
    737	    // any `add` or `remove` events. Fires `reset` when finished.
    738	    reset: function(models, options) {
    739	      models  || (models = []);
    740	      options || (options = {});
    741	      for (var i = 0, l = this.models.length; i < l; i++) {
    742	        this._removeReference(this.models[i]);
    743	      }
    744	      this._reset();
    745	      this.add(models, _.extend({silent: true}, options));
    746	      if (!options.silent) this.trigger('reset', this, options);
    747	      return this;
    748	    },
    749	
    750	    // Fetch the default set of models for this collection, resetting the
    751	    // collection when they arrive. If `add: true` is passed, appends the
    752	    // models to the collection instead of resetting.
    753	    fetch: function(options) {
    754	      options = options ? _.clone(options) : {};
    755	      if (options.parse === undefined) options.parse = true;
    756	      var collection = this;
    757	      var success = options.success;
    758	      options.success = function(resp, status, xhr) {
    759	        collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
    760	        if (success) success(collection, resp);
    761	      };
    762	      options.error = Backbone.wrapError(options.error, collection, options);
    763	      return (this.sync || Backbone.sync).call(this, 'read', this, options);
    764	    },
    765	
    766	    // Create a new instance of a model in this collection. Add the model to the
    767	    // collection immediately, unless `wait: true` is passed, in which case we
    768	    // wait for the server to agree.
    769	    create: function(model, options) {
    770	      var coll = this;
    771	      options = options ? _.clone(options) : {};
    772	      model = this._prepareModel(model, options);
    773	      if (!model) return false;
    774	      if (!options.wait) coll.add(model, options);
    775	      var success = options.success;
    776	      options.success = function(nextModel, resp, xhr) {
    777	        if (options.wait) coll.add(nextModel, options);
    778	        if (success) {
    779	          success(nextModel, resp);
    780	        } else {
    781	          nextModel.trigger('sync', model, resp, options);
    782	        }
    783	      };
    784	      model.save(null, options);
    785	      return model;
    786	    },
    787	
    788	    // **parse** converts a response into a list of models to be added to the
    789	    // collection. The default implementation is just to pass it through.
    790	    parse: function(resp, xhr) {
    791	      return resp;
    792	    },
    793	
    794	    // Proxy to _'s chain. Can't be proxied the same way the rest of the
    795	    // underscore methods are proxied because it relies on the underscore
    796	    // constructor.
    797	    chain: function () {
    798	      return _(this.models).chain();
    799	    },
    800	
    801	    // Reset all internal state. Called when the collection is reset.
    802	    _reset: function(options) {
    803	      this.length = 0;
    804	      this.models = [];
    805	      this._byId  = {};
    806	      this._byCid = {};
    807	    },
    808	
    809	    // Prepare a model or hash of attributes to be added to this collection.
    810	    _prepareModel: function(model, options) {
    811	      options || (options = {});
    812	      if (!(model instanceof Model)) {
    813	        var attrs = model;
    814	        options.collection = this;
    815	        model = new this.model(attrs, options);
    816	        if (!model._validate(model.attributes, options)) model = false;
    817	      } else if (!model.collection) {
    818	        model.collection = this;
    819	      }
    820	      return model;
    821	    },
    822	
    823	    // Internal method to remove a model's ties to a collection.
    824	    _removeReference: function(model) {
    825	      if (this == model.collection) {
    826	        delete model.collection;
    827	      }
    828	      model.off('all', this._onModelEvent, this);
    829	    },
    830	
    831	    // Internal method called every time a model in the set fires an event.
    832	    // Sets need to update their indexes when models change ids. All other
    833	    // events simply proxy through. "add" and "remove" events that originate
    834	    // in other collections are ignored.
    835	    _onModelEvent: function(event, model, collection, options) {
    836	      if ((event == 'add' || event == 'remove') && collection != this) return;
    837	      if (event == 'destroy') {
    838	        this.remove(model, options);
    839	      }
    840	      if (model && event === 'change:' + model.idAttribute) {
    841	        delete this._byId[model.previous(model.idAttribute)];
    842	        this._byId[model.id] = model;
    843	      }
    844	      this.trigger.apply(this, arguments);
    845	    }
    846	
    847	  });
    848	
    849	  // Underscore methods that we want to implement on the Collection.
    850	  var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find',
    851	    'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any',
    852	    'include', 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex',
    853	    'toArray', 'size', 'first', 'initial', 'rest', 'last', 'without', 'indexOf',
    854	    'shuffle', 'lastIndexOf', 'isEmpty', 'groupBy'];
    855	
    856	  // Mix in each Underscore method as a proxy to `Collection#models`.
    857	  _.each(methods, function(method) {
    858	    Collection.prototype[method] = function() {
    859	      return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
    860	    };
    861	  });
    862	
    863	  // Backbone.Router
    864	  // -------------------
    865	
    866	  // Routers map faux-URLs to actions, and fire events when routes are
    867	  // matched. Creating a new one sets its `routes` hash, if not set statically.
    868	  var Router = Backbone.Router = function(options) {
    869	    options || (options = {});
    870	    if (options.routes) this.routes = options.routes;
    871	    this._bindRoutes();
    872	    this.initialize.apply(this, arguments);
    873	  };
    874	
    875	  // Cached regular expressions for matching named param parts and splatted
    876	  // parts of route strings.
    877	  var namedParam    = /:\w+/g;
    878	  var splatParam    = /\*\w+/g;
    879	  var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;
    880	
    881	  // Set up all inheritable **Backbone.Router** properties and methods.
    882	  _.extend(Router.prototype, Events, {
    883	
    884	    // Initialize is an empty function by default. Override it with your own
    885	    // initialization logic.
    886	    initialize: function(){},
    887	
    888	    // Manually bind a single named route to a callback. For example:
    889	    //
    890	    //     this.route('search/:query/p:num', 'search', function(query, num) {
    891	    //       ...
    892	    //     });
    893	    //
    894	    route: function(route, name, callback) {
    895	      Backbone.history || (Backbone.history = new History);
    896	      if (!_.isRegExp(route)) route = this._routeToRegExp(route);
    897	      if (!callback) callback = this[name];
    898	      Backbone.history.route(route, _.bind(function(fragment) {
    899	        var args = this._extractParameters(route, fragment);
    900	        callback && callback.apply(this, args);
    901	        this.trigger.apply(this, ['route:' + name].concat(args));
    902	        Backbone.history.trigger('route', this, name, args);
    903	      }, this));
    904	      return this;
    905	    },
    906	
    907	    // Simple proxy to `Backbone.history` to save a fragment into the history.
    908	    navigate: function(fragment, options) {
    909	      Backbone.history.navigate(fragment, options);
    910	    },
    911	
    912	    // Bind all defined routes to `Backbone.history`. We have to reverse the
    913	    // order of the routes here to support behavior where the most general
    914	    // routes can be defined at the bottom of the route map.
    915	    _bindRoutes: function() {
    916	      if (!this.routes) return;
    917	      var routes = [];
    918	      for (var route in this.routes) {
    919	        routes.unshift([route, this.routes[route]]);
    920	      }
    921	      for (var i = 0, l = routes.length; i < l; i++) {
    922	        this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
    923	      }
    924	    },
    925	
    926	    // Convert a route string into a regular expression, suitable for matching
    927	    // against the current location hash.
    928	    _routeToRegExp: function(route) {
    929	      route = route.replace(escapeRegExp, '\\$&')
    930	                   .replace(namedParam, '([^\/]+)')
    931	                   .replace(splatParam, '(.*?)');
    932	      return new RegExp('^' + route + '$');
    933	    },
    934	
    935	    // Given a route, and a URL fragment that it matches, return the array of
    936	    // extracted parameters.
    937	    _extractParameters: function(route, fragment) {
    938	      return route.exec(fragment).slice(1);
    939	    }
    940	
    941	  });
    942	
    943	  // Backbone.History
    944	  // ----------------
    945	
    946	  // Handles cross-browser history management, based on URL fragments. If the
    947	  // browser does not support `onhashchange`, falls back to polling.
    948	  var History = Backbone.History = function() {
    949	    this.handlers = [];
    950	    _.bindAll(this, 'checkUrl');
    951	  };
    952	
    953	  // Cached regex for cleaning leading hashes and slashes .
    954	  var routeStripper = /^[#\/]/;
    955	
    956	  // Cached regex for detecting MSIE.
    957	  var isExplorer = /msie [\w.]+/;
    958	
    959	  // Has the history handling already been started?
    960	  History.started = false;
    961	
    962	  // Set up all inheritable **Backbone.History** properties and methods.
    963	  _.extend(History.prototype, Events, {
    964	
    965	    // The default interval to poll for hash changes, if necessary, is
    966	    // twenty times a second.
    967	    interval: 50,
    968	
    969	    // Gets the true hash value. Cannot use location.hash directly due to bug
    970	    // in Firefox where location.hash will always be decoded.
    971	    getHash: function(windowOverride) {
    972	      var loc = windowOverride ? windowOverride.location : window.location;
    973	      var match = loc.href.match(/#(.*)$/);
    974	      return match ? match[1] : '';
    975	    },
    976	
    977	    // Get the cross-browser normalized URL fragment, either from the URL,
    978	    // the hash, or the override.
    979	    getFragment: function(fragment, forcePushState) {
    980	      if (fragment == null) {
    981	        if (this._hasPushState || forcePushState) {
    982	          fragment = window.location.pathname;
    983	          var search = window.location.search;
    984	          if (search) fragment += search;
    985	        } else {
    986	          fragment = this.getHash();
    987	        }
    988	      }
    989	      if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length);
    990	      return fragment.replace(routeStripper, '');
    991	    },
    992	
    993	    // Start the hash change handling, returning `true` if the current URL matches
    994	    // an existing route, and `false` otherwise.
    995	    start: function(options) {
    996	      if (History.started) throw new Error("Backbone.history has already been started");
    997	      History.started = true;
    998	
    999	      // Figure out the initial configuration. Do we need an iframe?
    1000	      // Is pushState desired ... is it available?
    1001	      this.options          = _.extend({}, {root: '/'}, this.options, options);
    1002	      this._wantsHashChange = this.options.hashChange !== false;
    1003	      this._wantsPushState  = !!this.options.pushState;
    1004	      this._hasPushState    = !!(this.options.pushState && window.history && window.history.pushState);
    1005	      var fragment          = this.getFragment();
    1006	      var docMode           = document.documentMode;
    1007	      var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
    1008	
    1009	      if (oldIE) {
    1010	        this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
    1011	        this.navigate(fragment);
    1012	      }
    1013	
    1014	      // Depending on whether we're using pushState or hashes, and whether
    1015	      // 'onhashchange' is supported, determine how we check the URL state.
    1016	      if (this._hasPushState) {
    1017	        $(window).bind('popstate', this.checkUrl);
    1018	      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
    1019	        $(window).bind('hashchange', this.checkUrl);
    1020	      } else if (this._wantsHashChange) {
    1021	        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
    1022	      }
    1023	
    1024	      // Determine if we need to change the base url, for a pushState link
    1025	      // opened by a non-pushState browser.
    1026	      this.fragment = fragment;
    1027	      var loc = window.location;
    1028	      var atRoot  = loc.pathname == this.options.root;
    1029	
    1030	      // If we've started off with a route from a `pushState`-enabled browser,
    1031	      // but we're currently in a browser that doesn't support it...
    1032	      if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
    1033	        this.fragment = this.getFragment(null, true);
    1034	        window.location.replace(this.options.root + '#' + this.fragment);
    1035	        // Return immediately as browser will do redirect to new url
    1036	        return true;
    1037	
    1038	      // Or if we've started out with a hash-based route, but we're currently
    1039	      // in a browser where it could be `pushState`-based instead...
    1040	      } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
    1041	        this.fragment = this.getHash().replace(routeStripper, '');
    1042	        window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
    1043	      }
    1044	
    1045	      if (!this.options.silent) {
    1046	        return this.loadUrl();
    1047	      }
    1048	    },
    1049	
    1050	    // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
    1051	    // but possibly useful for unit testing Routers.
    1052	    stop: function() {
    1053	      $(window).unbind('popstate', this.checkUrl).unbind('hashchange', this.checkUrl);
    1054	      clearInterval(this._checkUrlInterval);
    1055	      History.started = false;
    1056	    },
    1057	
    1058	    // Add a route to be tested when the fragment changes. Routes added later
    1059	    // may override previous routes.
    1060	    route: function(route, callback) {
    1061	      this.handlers.unshift({route: route, callback: callback});
    1062	    },
    1063	
    1064	    // Checks the current URL to see if it has changed, and if it has,
    1065	    // calls `loadUrl`, normalizing across the hidden iframe.
    1066	    checkUrl: function(e) {
    1067	      var current = this.getFragment();
    1068	      if (current == this.fragment && this.iframe) current = this.getFragment(this.getHash(this.iframe));
    1069	      if (current == this.fragment) return false;
    1070	      if (this.iframe) this.navigate(current);
    1071	      this.loadUrl() || this.loadUrl(this.getHash());
    1072	    },
    1073	
    1074	    // Attempt to load the current URL fragment. If a route succeeds with a
    1075	    // match, returns `true`. If no defined routes matches the fragment,
    1076	    // returns `false`.
    1077	    loadUrl: function(fragmentOverride) {
    1078	      var fragment = this.fragment = this.getFragment(fragmentOverride);
    1079	      var matched = _.any(this.handlers, function(handler) {
    1080	        if (handler.route.test(fragment)) {
    1081	          handler.callback(fragment);
    1082	          return true;
    1083	        }
    1084	      });
    1085	      return matched;
    1086	    },
    1087	
    1088	    // Save a fragment into the hash history, or replace the URL state if the
    1089	    // 'replace' option is passed. You are responsible for properly URL-encoding
    1090	    // the fragment in advance.
    1091	    //
    1092	    // The options object can contain `trigger: true` if you wish to have the
    1093	    // route callback be fired (not usually desirable), or `replace: true`, if
    1094	    // you wish to modify the current URL without adding an entry to the history.
    1095	    navigate: function(fragment, options) {
    1096	      if (!History.started) return false;
    1097	      if (!options || options === true) options = {trigger: options};
    1098	      var frag = (fragment || '').replace(routeStripper, '');
    1099	      if (this.fragment == frag) return;
    1100	
    1101	      // If pushState is available, we use it to set the fragment as a real URL.
    1102	      if (this._hasPushState) {
    1103	        if (frag.indexOf(this.options.root) != 0) frag = this.options.root + frag;
    1104	        this.fragment = frag;
    1105	        window.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, frag);
    1106	
    1107	      // If hash changes haven't been explicitly disabled, update the hash
    1108	      // fragment to store history.
    1109	      } else if (this._wantsHashChange) {
    1110	        this.fragment = frag;
    1111	        this._updateHash(window.location, frag, options.replace);
    1112	        if (this.iframe && (frag != this.getFragment(this.getHash(this.iframe)))) {
    1113	          // Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
    1114	          // When replace is true, we don't want this.
    1115	          if(!options.replace) this.iframe.document.open().close();
    1116	          this._updateHash(this.iframe.location, frag, options.replace);
    1117	        }
    1118	
    1119	      // If you've told us that you explicitly don't want fallback hashchange-
    1120	      // based history, then `navigate` becomes a page refresh.
    1121	      } else {
    1122	        window.location.assign(this.options.root + fragment);
    1123	      }
    1124	      if (options.trigger) this.loadUrl(fragment);
    1125	    },
    1126	
    1127	    // Update the hash location, either replacing the current entry, or adding
    1128	    // a new one to the browser history.
    1129	    _updateHash: function(location, fragment, replace) {
    1130	      if (replace) {
    1131	        location.replace(location.toString().replace(/(javascript:|#).*$/, '') + '#' + fragment);
    1132	      } else {
    1133	        location.hash = fragment;
    1134	      }
    1135	    }
    1136	  });
    1137	
    1138	  // Backbone.View
    1139	  // -------------
    1140	
    1141	  // Creating a Backbone.View creates its initial element outside of the DOM,
    1142	  // if an existing element is not provided...
    1143	  var View = Backbone.View = function(options) {
    1144	    this.cid = _.uniqueId('view');
    1145	    this._configure(options || {});
    1146	    this._ensureElement();
    1147	    this.initialize.apply(this, arguments);
    1148	    this.delegateEvents();
    1149	  };
    1150	
    1151	  // Cached regex to split keys for `delegate`.
    1152	  var delegateEventSplitter = /^(\S+)\s*(.*)$/;
    1153	
    1154	  // List of view options to be merged as properties.
    1155	  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];
    1156	
    1157	  // Set up all inheritable **Backbone.View** properties and methods.
    1158	  _.extend(View.prototype, Events, {
    1159	
    1160	    // The default `tagName` of a View's element is `"div"`.
    1161	    tagName: 'div',
    1162	
    1163	    // jQuery delegate for element lookup, scoped to DOM elements within the
    1164	    // current view. This should be prefered to global lookups where possible.
    1165	    $: function(selector) {
    1166	      return this.$el.find(selector);
    1167	    },
    1168	
    1169	    // Initialize is an empty function by default. Override it with your own
    1170	    // initialization logic.
    1171	    initialize: function(){},
    1172	
    1173	    // **render** is the core function that your view should override, in order
    1174	    // to populate its element (`this.el`), with the appropriate HTML. The
    1175	    // convention is for **render** to always return `this`.
    1176	    render: function() {
    1177	      return this;
    1178	    },
    1179	
    1180	    // Remove this view from the DOM. Note that the view isn't present in the
    1181	    // DOM by default, so calling this method may be a no-op.
    1182	    remove: function() {
    1183	      this.$el.remove();
    1184	      return this;
    1185	    },
    1186	
    1187	    // For small amounts of DOM Elements, where a full-blown template isn't
    1188	    // needed, use **make** to manufacture elements, one at a time.
    1189	    //
    1190	    //     var el = this.make('li', {'class': 'row'}, this.model.escape('title'));
    1191	    //
    1192	    make: function(tagName, attributes, content) {
    1193	      var el = document.createElement(tagName);
    1194	      if (attributes) $(el).attr(attributes);
    1195	      if (content) $(el).html(content);
    1196	      return el;
    1197	    },
    1198	
    1199	    // Change the view's element (`this.el` property), including event
    1200	    // re-delegation.
    1201	    setElement: function(element, delegate) {
    1202	      if (this.$el) this.undelegateEvents();
    1203	      this.$el = (element instanceof $) ? element : $(element);
    1204	      this.el = this.$el[0];
    1205	      if (delegate !== false) this.delegateEvents();
    1206	      return this;
    1207	    },
    1208	
    1209	    // Set callbacks, where `this.events` is a hash of
    1210	    //
    1211	    // *{"event selector": "callback"}*
    1212	    //
    1213	    //     {
    1214	    //       'mousedown .title':  'edit',
    1215	    //       'click .button':     'save'
    1216	    //       'click .open':       function(e) { ... }
    1217	    //     }
    1218	    //
    1219	    // pairs. Callbacks will be bound to the view, with `this` set properly.
    1220	    // Uses event delegation for efficiency.
    1221	    // Omitting the selector binds the event to `this.el`.
    1222	    // This only works for delegate-able events: not `focus`, `blur`, and
    1223	    // not `change`, `submit`, and `reset` in Internet Explorer.
    1224	    delegateEvents: function(events) {
    1225	      if (!(events || (events = getValue(this, 'events')))) return;
    1226	      this.undelegateEvents();
    1227	      for (var key in events) {
    1228	        var method = events[key];
    1229	        if (!_.isFunction(method)) method = this[events[key]];
    1230	        if (!method) throw new Error('Method "' + events[key] + '" does not exist');
    1231	        var match = key.match(delegateEventSplitter);
    1232	        var eventName = match[1], selector = match[2];
    1233	        method = _.bind(method, this);
    1234	        eventName += '.delegateEvents' + this.cid;
    1235	        if (selector === '') {
    1236	          this.$el.bind(eventName, method);
    1237	        } else {
    1238	          this.$el.delegate(selector, eventName, method);
    1239	        }
    1240	      }
    1241	    },
    1242	
    1243	    // Clears all callbacks previously bound to the view with `delegateEvents`.
    1244	    // You usually don't need to use this, but may wish to if you have multiple
    1245	    // Backbone views attached to the same DOM element.
    1246	    undelegateEvents: function() {
    1247	      this.$el.unbind('.delegateEvents' + this.cid);
    1248	    },
    1249	
    1250	    // Performs the initial configuration of a View with a set of options.
    1251	    // Keys with special meaning *(model, collection, id, className)*, are
    1252	    // attached directly to the view.
    1253	    _configure: function(options) {
    1254	      if (this.options) options = _.extend({}, this.options, options);
    1255	      for (var i = 0, l = viewOptions.length; i < l; i++) {
    1256	        var attr = viewOptions[i];
    1257	        if (options[attr]) this[attr] = options[attr];
    1258	      }
    1259	      this.options = options;
    1260	    },
    1261	
    1262	    // Ensure that the View has a DOM element to render into.
    1263	    // If `this.el` is a string, pass it through `$()`, take the first
    1264	    // matching element, and re-assign it to `el`. Otherwise, create
    1265	    // an element from the `id`, `className` and `tagName` properties.
    1266	    _ensureElement: function() {
    1267	      if (!this.el) {
    1268	        var attrs = getValue(this, 'attributes') || {};
    1269	        if (this.id) attrs.id = this.id;
    1270	        if (this.className) attrs['class'] = this.className;
    1271	        this.setElement(this.make(this.tagName, attrs), false);
    1272	      } else {
    1273	        this.setElement(this.el, false);
    1274	      }
    1275	    }
    1276	
    1277	  });
    1278	
    1279	  // The self-propagating extend function that Backbone classes use.
    1280	  var extend = function (protoProps, classProps) {
    1281	    var child = inherits(this, protoProps, classProps);
    1282	    child.extend = this.extend;
    1283	    return child;
    1284	  };
    1285	
    1286	  // Set up inheritance for the model, collection, and view.
    1287	  Model.extend = Collection.extend = Router.extend = View.extend = extend;
    1288	
    1289	  // Backbone.sync
    1290	  // -------------
    1291	
    1292	  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
    1293	  var methodMap = {
    1294	    'create': 'POST',
    1295	    'update': 'PUT',
    1296	    'delete': 'DELETE',
    1297	    'read':   'GET'
    1298	  };
    1299	
    1300	  // Override this function to change the manner in which Backbone persists
    1301	  // models to the server. You will be passed the type of request, and the
    1302	  // model in question. By default, makes a RESTful Ajax request
    1303	  // to the model's `url()`. Some possible customizations could be:
    1304	  //
    1305	  // * Use `setTimeout` to batch rapid-fire updates into a single request.
    1306	  // * Send up the models as XML instead of JSON.
    1307	  // * Persist models via WebSockets instead of Ajax.
    1308	  //
    1309	  // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
    1310	  // as `POST`, with a `_method` parameter containing the true HTTP method,
    1311	  // as well as all requests with the body as `application/x-www-form-urlencoded`
    1312	  // instead of `application/json` with the model in a param named `model`.
    1313	  // Useful when interfacing with server-side languages like **PHP** that make
    1314	  // it difficult to read the body of `PUT` requests.
    1315	  Backbone.sync = function(method, model, options) {
    1316	    var type = methodMap[method];
    1317	
    1318	    // Default options, unless specified.
    1319	    options || (options = {});
    1320	
    1321	    // Default JSON-request options.
    1322	    var params = {type: type, dataType: 'json'};
    1323	
    1324	    // Ensure that we have a URL.
    1325	    if (!options.url) {
    1326	      params.url = getValue(model, 'url') || urlError();
    1327	    }
    1328	
    1329	    // Ensure that we have the appropriate request data.
    1330	    if (!options.data && model && (method == 'create' || method == 'update')) {
    1331	      params.contentType = 'application/json';
    1332	      params.data = JSON.stringify(model.toJSON());
    1333	    }
    1334	
    1335	    // For older servers, emulate JSON by encoding the request into an HTML-form.
    1336	    if (Backbone.emulateJSON) {
    1337	      params.contentType = 'application/x-www-form-urlencoded';
    1338	      params.data = params.data ? {model: params.data} : {};
    1339	    }
    1340	
    1341	    // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
    1342	    // And an `X-HTTP-Method-Override` header.
    1343	    if (Backbone.emulateHTTP) {
    1344	      if (type === 'PUT' || type === 'DELETE') {
    1345	        if (Backbone.emulateJSON) params.data._method = type;
    1346	        params.type = 'POST';
    1347	        params.beforeSend = function(xhr) {
    1348	          xhr.setRequestHeader('X-HTTP-Method-Override', type);
    1349	        };
    1350	      }
    1351	    }
    1352	
    1353	    // Don't process data on a non-GET request.
    1354	    if (params.type !== 'GET' && !Backbone.emulateJSON) {
    1355	      params.processData = false;
    1356	    }
    1357	
    1358	    // Make the request, allowing the user to override any Ajax options.
    1359	    return $.ajax(_.extend(params, options));
    1360	  };
    1361	
    1362	  // Wrap an optional error callback with a fallback error event.
    1363	  Backbone.wrapError = function(onError, originalModel, options) {
    1364	    return function(model, resp) {
    1365	      resp = model === originalModel ? resp : model;
    1366	      if (onError) {
    1367	        onError(originalModel, resp, options);
    1368	      } else {
    1369	        originalModel.trigger('error', originalModel, resp, options);
    1370	      }
    1371	    };
    1372	  };
    1373	
    1374	  // Helpers
    1375	  // -------
    1376	
    1377	  // Shared empty constructor function to aid in prototype-chain creation.
    1378	  var ctor = function(){};
    1379	
    1380	  // Helper function to correctly set up the prototype chain, for subclasses.
    1381	  // Similar to `goog.inherits`, but uses a hash of prototype properties and
    1382	  // class properties to be extended.
    1383	  var inherits = function(parent, protoProps, staticProps) {
    1384	    var child;
    1385	
    1386	    // The constructor function for the new subclass is either defined by you
    1387	    // (the "constructor" property in your `extend` definition), or defaulted
    1388	    // by us to simply call the parent's constructor.
    1389	    if (protoProps && protoProps.hasOwnProperty('constructor')) {
    1390	      child = protoProps.constructor;
    1391	    } else {
    1392	      child = function(){ parent.apply(this, arguments); };
    1393	    }
    1394	
    1395	    // Inherit class (static) properties from parent.
    1396	    _.extend(child, parent);
    1397	
    1398	    // Set the prototype chain to inherit from `parent`, without calling
    1399	    // `parent`'s constructor function.
    1400	    ctor.prototype = parent.prototype;
    1401	    child.prototype = new ctor();
    1402	
    1403	    // Add prototype properties (instance properties) to the subclass,
    1404	    // if supplied.
    1405	    if (protoProps) _.extend(child.prototype, protoProps);
    1406	
    1407	    // Add static properties to the constructor function, if supplied.
    1408	    if (staticProps) _.extend(child, staticProps);
    1409	
    1410	    // Correctly set child's `prototype.constructor`.
    1411	    child.prototype.constructor = child;
    1412	
    1413	    // Set a convenience property in case the parent's prototype is needed later.
    1414	    child.__super__ = parent.prototype;
    1415	
    1416	    return child;
    1417	  };
    1418	
    1419	  // Helper function to get a value from a Backbone object as a property
    1420	  // or as a function.
    1421	  var getValue = function(object, prop) {
    1422	    if (!(object && object[prop])) return null;
    1423	    return _.isFunction(object[prop]) ? object[prop]() : object[prop];
    1424	  };
    1425	
    1426	  // Throw an error when a URL is needed, and none is supplied.
    1427	  var urlError = function() {
    1428	    throw new Error('A "url" property or function must be specified');
    1429	  };
    1430	
    1431	}).call(this);