Make WordPress Core

Changeset 36546


Ignore:
Timestamp:
02/17/2016 03:21:09 PM (9 years ago)
Author:
ocean90
Message:

Update Backbone and Underscore to the latest versions.

Backbone, from 1.1.2 to 1.2.3. Underscore, from 1.6.0 to 1.8.3.

The new versions of Backbone and Underscore offer numerous small bug fixes and some optimizations and other improvements. Check the Backbone changelog and Underscore changelog for the full details.

The new versions include some significant changes that may break existing code. Plugins or themes that rely on the bundled Backbone and/or Underscore libraries should carefully check functionality with the latest versions and run any available unit tests to ensure compatibility.

Some changes of note that were addressed in core as part of this upgrade:

  • _.flatten no longer works with objects since Underscore.js 1.7. _.flatten() working with objects was an unintended side-affect of the implementation, see underscore#1904. Check any _flatten usage and only flatten arrays.
  • As of Backbone 1.2.0, you can no longer modify the events hash or your view's el property in initialize, so don't try to modify them there.
  • Since Underscore 1.7, Underscore templates no longer accept an initial data object. _.template always returns a function now so make sure you use it that way.

Props adamsilverstein.
Fixes #34350.

Location:
trunk/src
Files:
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/js/customize-widgets.js

    r36522 r36546  
    664664        _setupReorderUI: function() {
    665665            var self = this, selectSidebarItem, $moveWidgetArea,
    666                 $reorderNav, updateAvailableSidebars;
     666                $reorderNav, updateAvailableSidebars, template;
    667667
    668668            /**
     
    682682             */
    683683            this.container.find( '.widget-title-action' ).after( $( api.Widgets.data.tpl.widgetReorderNav ) );
    684             $moveWidgetArea = $(
    685                 _.template( api.Widgets.data.tpl.moveWidgetArea, {
     684
     685
     686            template = _.template( api.Widgets.data.tpl.moveWidgetArea );
     687            $moveWidgetArea = $( template( {
    686688                    sidebars: _( api.Widgets.registeredSidebars.toArray() ).pluck( 'attributes' )
    687689                } )
  • trunk/src/wp-includes/js/backbone.js

    r31471 r36546  
    1 //     Backbone.js 1.1.2
    2 
    3 //     (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
     1//     Backbone.js 1.2.3
     2
     3//     (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
    44//     Backbone may be freely distributed under the MIT license.
    55//     For all details and documentation:
    66//     http://backbonejs.org
    77
    8 (function(root, factory) {
     8(function(factory) {
     9
     10  // Establish the root object, `window` (`self`) in the browser, or `global` on the server.
     11  // We use `self` instead of `window` for `WebWorker` support.
     12  var root = (typeof self == 'object' && self.self == self && self) ||
     13            (typeof global == 'object' && global.global == global && global);
    914
    1015  // Set up Backbone appropriately for the environment. Start with AMD.
     
    1823  // Next for Node.js or CommonJS. jQuery may not be needed as a module.
    1924  } else if (typeof exports !== 'undefined') {
    20     var _ = require('underscore');
    21     factory(root, exports, _);
     25    var _ = require('underscore'), $;
     26    try { $ = require('jquery'); } catch(e) {}
     27    factory(root, exports, _, $);
    2228
    2329  // Finally, as a browser global.
     
    2632  }
    2733
    28 }(this, function(root, Backbone, _, $) {
     34}(function(root, Backbone, _, $) {
    2935
    3036  // Initial Setup
     
    3541  var previousBackbone = root.Backbone;
    3642
    37   // Create local references to array methods we'll want to use later.
    38   var array = [];
    39   var push = array.push;
    40   var slice = array.slice;
    41   var splice = array.splice;
     43  // Create a local reference to a common array method we'll want to use later.
     44  var slice = Array.prototype.slice;
    4245
    4346  // Current version of the library. Keep in sync with `package.json`.
    44   Backbone.VERSION = '1.1.2';
     47  Backbone.VERSION = '1.2.3';
    4548
    4649  // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
     
    6164
    6265  // Turn on `emulateJSON` to support legacy servers that can't deal with direct
    63   // `application/json` requests ... will encode the body as
     66  // `application/json` requests ... this will encode the body as
    6467  // `application/x-www-form-urlencoded` instead and will send the model in a
    6568  // form param named `model`.
    6669  Backbone.emulateJSON = false;
    6770
     71  // Proxy Backbone class methods to Underscore functions, wrapping the model's
     72  // `attributes` object or collection's `models` array behind the scenes.
     73  //
     74  // collection.filter(function(model) { return model.get('age') > 10 });
     75  // collection.each(this.addView);
     76  //
     77  // `Function#apply` can be slow so we use the method's arg count, if we know it.
     78  var addMethod = function(length, method, attribute) {
     79    switch (length) {
     80      case 1: return function() {
     81        return _[method](this[attribute]);
     82      };
     83      case 2: return function(value) {
     84        return _[method](this[attribute], value);
     85      };
     86      case 3: return function(iteratee, context) {
     87        return _[method](this[attribute], cb(iteratee, this), context);
     88      };
     89      case 4: return function(iteratee, defaultVal, context) {
     90        return _[method](this[attribute], cb(iteratee, this), defaultVal, context);
     91      };
     92      default: return function() {
     93        var args = slice.call(arguments);
     94        args.unshift(this[attribute]);
     95        return _[method].apply(_, args);
     96      };
     97    }
     98  };
     99  var addUnderscoreMethods = function(Class, methods, attribute) {
     100    _.each(methods, function(length, method) {
     101      if (_[method]) Class.prototype[method] = addMethod(length, method, attribute);
     102    });
     103  };
     104
     105  // Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`.
     106  var cb = function(iteratee, instance) {
     107    if (_.isFunction(iteratee)) return iteratee;
     108    if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee);
     109    if (_.isString(iteratee)) return function(model) { return model.get(iteratee); };
     110    return iteratee;
     111  };
     112  var modelMatcher = function(attrs) {
     113    var matcher = _.matches(attrs);
     114    return function(model) {
     115      return matcher(model.attributes);
     116    };
     117  };
     118
    68119  // Backbone.Events
    69120  // ---------------
    70121
    71122  // A module that can be mixed in to *any object* in order to provide it with
    72   // custom events. You may bind with `on` or remove with `off` callback
    73   // functions to an event; `trigger`-ing an event fires all callbacks in
     123  // a custom event channel. You may bind a callback to an event with `on` or
     124  // remove with `off`; `trigger`-ing an event fires all callbacks in
    74125  // succession.
    75126  //
     
    79130  //     object.trigger('expand');
    80131  //
    81   var Events = Backbone.Events = {
    82 
    83     // Bind an event to a `callback` function. Passing `"all"` will bind
    84     // the callback to all events fired.
    85     on: function(name, callback, context) {
    86       if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
    87       this._events || (this._events = {});
    88       var events = this._events[name] || (this._events[name] = []);
    89       events.push({callback: callback, context: context, ctx: context || this});
    90       return this;
    91     },
    92 
    93     // Bind an event to only be triggered a single time. After the first time
    94     // the callback is invoked, it will be removed.
    95     once: function(name, callback, context) {
    96       if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
    97       var self = this;
    98       var once = _.once(function() {
    99         self.off(name, once);
     132  var Events = Backbone.Events = {};
     133
     134  // Regular expression used to split event strings.
     135  var eventSplitter = /\s+/;
     136
     137  // Iterates over the standard `event, callback` (as well as the fancy multiple
     138  // space-separated events `"change blur", callback` and jQuery-style event
     139  // maps `{event: callback}`).
     140  var eventsApi = function(iteratee, events, name, callback, opts) {
     141    var i = 0, names;
     142    if (name && typeof name === 'object') {
     143      // Handle event maps.
     144      if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
     145      for (names = _.keys(name); i < names.length ; i++) {
     146        events = eventsApi(iteratee, events, names[i], name[names[i]], opts);
     147      }
     148    } else if (name && eventSplitter.test(name)) {
     149      // Handle space separated event names by delegating them individually.
     150      for (names = name.split(eventSplitter); i < names.length; i++) {
     151        events = iteratee(events, names[i], callback, opts);
     152      }
     153    } else {
     154      // Finally, standard events.
     155      events = iteratee(events, name, callback, opts);
     156    }
     157    return events;
     158  };
     159
     160  // Bind an event to a `callback` function. Passing `"all"` will bind
     161  // the callback to all events fired.
     162  Events.on = function(name, callback, context) {
     163    return internalOn(this, name, callback, context);
     164  };
     165
     166  // Guard the `listening` argument from the public API.
     167  var internalOn = function(obj, name, callback, context, listening) {
     168    obj._events = eventsApi(onApi, obj._events || {}, name, callback, {
     169        context: context,
     170        ctx: obj,
     171        listening: listening
     172    });
     173
     174    if (listening) {
     175      var listeners = obj._listeners || (obj._listeners = {});
     176      listeners[listening.id] = listening;
     177    }
     178
     179    return obj;
     180  };
     181
     182  // Inversion-of-control versions of `on`. Tell *this* object to listen to
     183  // an event in another object... keeping track of what it's listening to
     184  // for easier unbinding later.
     185  Events.listenTo =  function(obj, name, callback) {
     186    if (!obj) return this;
     187    var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
     188    var listeningTo = this._listeningTo || (this._listeningTo = {});
     189    var listening = listeningTo[id];
     190
     191    // This object is not listening to any other events on `obj` yet.
     192    // Setup the necessary references to track the listening callbacks.
     193    if (!listening) {
     194      var thisId = this._listenId || (this._listenId = _.uniqueId('l'));
     195      listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0};
     196    }
     197
     198    // Bind callbacks on obj, and keep track of them on listening.
     199    internalOn(obj, name, callback, this, listening);
     200    return this;
     201  };
     202
     203  // The reducing API that adds a callback to the `events` object.
     204  var onApi = function(events, name, callback, options) {
     205    if (callback) {
     206      var handlers = events[name] || (events[name] = []);
     207      var context = options.context, ctx = options.ctx, listening = options.listening;
     208      if (listening) listening.count++;
     209
     210      handlers.push({ callback: callback, context: context, ctx: context || ctx, listening: listening });
     211    }
     212    return events;
     213  };
     214
     215  // Remove one or many callbacks. If `context` is null, removes all
     216  // callbacks with that function. If `callback` is null, removes all
     217  // callbacks for the event. If `name` is null, removes all bound
     218  // callbacks for all events.
     219  Events.off =  function(name, callback, context) {
     220    if (!this._events) return this;
     221    this._events = eventsApi(offApi, this._events, name, callback, {
     222        context: context,
     223        listeners: this._listeners
     224    });
     225    return this;
     226  };
     227
     228  // Tell this object to stop listening to either specific events ... or
     229  // to every object it's currently listening to.
     230  Events.stopListening =  function(obj, name, callback) {
     231    var listeningTo = this._listeningTo;
     232    if (!listeningTo) return this;
     233
     234    var ids = obj ? [obj._listenId] : _.keys(listeningTo);
     235
     236    for (var i = 0; i < ids.length; i++) {
     237      var listening = listeningTo[ids[i]];
     238
     239      // If listening doesn't exist, this object is not currently
     240      // listening to obj. Break out early.
     241      if (!listening) break;
     242
     243      listening.obj.off(name, callback, this);
     244    }
     245    if (_.isEmpty(listeningTo)) this._listeningTo = void 0;
     246
     247    return this;
     248  };
     249
     250  // The reducing API that removes a callback from the `events` object.
     251  var offApi = function(events, name, callback, options) {
     252    if (!events) return;
     253
     254    var i = 0, listening;
     255    var context = options.context, listeners = options.listeners;
     256
     257    // Delete all events listeners and "drop" events.
     258    if (!name && !callback && !context) {
     259      var ids = _.keys(listeners);
     260      for (; i < ids.length; i++) {
     261        listening = listeners[ids[i]];
     262        delete listeners[listening.id];
     263        delete listening.listeningTo[listening.objId];
     264      }
     265      return;
     266    }
     267
     268    var names = name ? [name] : _.keys(events);
     269    for (; i < names.length; i++) {
     270      name = names[i];
     271      var handlers = events[name];
     272
     273      // Bail out if there are no events stored.
     274      if (!handlers) break;
     275
     276      // Replace events if there are any remaining.  Otherwise, clean up.
     277      var remaining = [];
     278      for (var j = 0; j < handlers.length; j++) {
     279        var handler = handlers[j];
     280        if (
     281          callback && callback !== handler.callback &&
     282            callback !== handler.callback._callback ||
     283              context && context !== handler.context
     284        ) {
     285          remaining.push(handler);
     286        } else {
     287          listening = handler.listening;
     288          if (listening && --listening.count === 0) {
     289            delete listeners[listening.id];
     290            delete listening.listeningTo[listening.objId];
     291          }
     292        }
     293      }
     294
     295      // Update tail event if the list has any events.  Otherwise, clean up.
     296      if (remaining.length) {
     297        events[name] = remaining;
     298      } else {
     299        delete events[name];
     300      }
     301    }
     302    if (_.size(events)) return events;
     303  };
     304
     305  // Bind an event to only be triggered a single time. After the first time
     306  // the callback is invoked, its listener will be removed. If multiple events
     307  // are passed in using the space-separated syntax, the handler will fire
     308  // once for each event, not once for a combination of all events.
     309  Events.once =  function(name, callback, context) {
     310    // Map the event into a `{event: once}` object.
     311    var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this));
     312    return this.on(events, void 0, context);
     313  };
     314
     315  // Inversion-of-control versions of `once`.
     316  Events.listenToOnce =  function(obj, name, callback) {
     317    // Map the event into a `{event: once}` object.
     318    var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj));
     319    return this.listenTo(obj, events);
     320  };
     321
     322  // Reduces the event callbacks into a map of `{event: onceWrapper}`.
     323  // `offer` unbinds the `onceWrapper` after it has been called.
     324  var onceMap = function(map, name, callback, offer) {
     325    if (callback) {
     326      var once = map[name] = _.once(function() {
     327        offer(name, once);
    100328        callback.apply(this, arguments);
    101329      });
    102330      once._callback = callback;
    103       return this.on(name, once, context);
    104     },
    105 
    106     // Remove one or many callbacks. If `context` is null, removes all
    107     // callbacks with that function. If `callback` is null, removes all
    108     // callbacks for the event. If `name` is null, removes all bound
    109     // callbacks for all events.
    110     off: function(name, callback, context) {
    111       var retain, ev, events, names, i, l, j, k;
    112       if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
    113       if (!name && !callback && !context) {
    114         this._events = void 0;
    115         return this;
    116       }
    117       names = name ? [name] : _.keys(this._events);
    118       for (i = 0, l = names.length; i < l; i++) {
    119         name = names[i];
    120         if (events = this._events[name]) {
    121           this._events[name] = retain = [];
    122           if (callback || context) {
    123             for (j = 0, k = events.length; j < k; j++) {
    124               ev = events[j];
    125               if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
    126                   (context && context !== ev.context)) {
    127                 retain.push(ev);
    128               }
    129             }
    130           }
    131           if (!retain.length) delete this._events[name];
    132         }
    133       }
    134 
    135       return this;
    136     },
    137 
    138     // Trigger one or many events, firing all bound callbacks. Callbacks are
    139     // passed the same arguments as `trigger` is, apart from the event name
    140     // (unless you're listening on `"all"`, which will cause your callback to
    141     // receive the true name of the event as the first argument).
    142     trigger: function(name) {
    143       if (!this._events) return this;
    144       var args = slice.call(arguments, 1);
    145       if (!eventsApi(this, 'trigger', name, args)) return this;
    146       var events = this._events[name];
    147       var allEvents = this._events.all;
     331    }
     332    return map;
     333  };
     334
     335  // Trigger one or many events, firing all bound callbacks. Callbacks are
     336  // passed the same arguments as `trigger` is, apart from the event name
     337  // (unless you're listening on `"all"`, which will cause your callback to
     338  // receive the true name of the event as the first argument).
     339  Events.trigger =  function(name) {
     340    if (!this._events) return this;
     341
     342    var length = Math.max(0, arguments.length - 1);
     343    var args = Array(length);
     344    for (var i = 0; i < length; i++) args[i] = arguments[i + 1];
     345
     346    eventsApi(triggerApi, this._events, name, void 0, args);
     347    return this;
     348  };
     349
     350  // Handles triggering the appropriate event callbacks.
     351  var triggerApi = function(objEvents, name, cb, args) {
     352    if (objEvents) {
     353      var events = objEvents[name];
     354      var allEvents = objEvents.all;
     355      if (events && allEvents) allEvents = allEvents.slice();
    148356      if (events) triggerEvents(events, args);
    149       if (allEvents) triggerEvents(allEvents, arguments);
    150       return this;
    151     },
    152 
    153     // Tell this object to stop listening to either specific events ... or
    154     // to every object it's currently listening to.
    155     stopListening: function(obj, name, callback) {
    156       var listeningTo = this._listeningTo;
    157       if (!listeningTo) return this;
    158       var remove = !name && !callback;
    159       if (!callback && typeof name === 'object') callback = this;
    160       if (obj) (listeningTo = {})[obj._listenId] = obj;
    161       for (var id in listeningTo) {
    162         obj = listeningTo[id];
    163         obj.off(name, callback, this);
    164         if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
    165       }
    166       return this;
    167     }
    168 
    169   };
    170 
    171   // Regular expression used to split event strings.
    172   var eventSplitter = /\s+/;
    173 
    174   // Implement fancy features of the Events API such as multiple event
    175   // names `"change blur"` and jQuery-style event maps `{change: action}`
    176   // in terms of the existing API.
    177   var eventsApi = function(obj, action, name, rest) {
    178     if (!name) return true;
    179 
    180     // Handle event maps.
    181     if (typeof name === 'object') {
    182       for (var key in name) {
    183         obj[action].apply(obj, [key, name[key]].concat(rest));
    184       }
    185       return false;
    186     }
    187 
    188     // Handle space separated event names.
    189     if (eventSplitter.test(name)) {
    190       var names = name.split(eventSplitter);
    191       for (var i = 0, l = names.length; i < l; i++) {
    192         obj[action].apply(obj, [names[i]].concat(rest));
    193       }
    194       return false;
    195     }
    196 
    197     return true;
     357      if (allEvents) triggerEvents(allEvents, [name].concat(args));
     358    }
     359    return objEvents;
    198360  };
    199361
     
    212374  };
    213375
    214   var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
    215 
    216   // Inversion-of-control versions of `on` and `once`. Tell *this* object to
    217   // listen to an event in another object ... keeping track of what it's
    218   // listening to.
    219   _.each(listenMethods, function(implementation, method) {
    220     Events[method] = function(obj, name, callback) {
    221       var listeningTo = this._listeningTo || (this._listeningTo = {});
    222       var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
    223       listeningTo[id] = obj;
    224       if (!callback && typeof name === 'object') callback = this;
    225       obj[implementation](name, callback, this);
    226       return this;
    227     };
    228   });
    229 
    230376  // Aliases for backwards compatibility.
    231377  Events.bind   = Events.on;
     
    249395    var attrs = attributes || {};
    250396    options || (options = {});
    251     this.cid = _.uniqueId('c');
     397    this.cid = _.uniqueId(this.cidPrefix);
    252398    this.attributes = {};
    253399    if (options.collection) this.collection = options.collection;
     
    272418    idAttribute: 'id',
    273419
     420    // The prefix is used to create the client id which is used to identify models locally.
     421    // You may want to override this if you're experiencing name clashes with model ids.
     422    cidPrefix: 'c',
     423
    274424    // Initialize is an empty function by default. Override it with your own
    275425    // initialization logic.
     
    303453    },
    304454
     455    // Special-cased proxy to underscore's `_.matches` method.
     456    matches: function(attrs) {
     457      return !!_.iteratee(attrs, this)(this.attributes);
     458    },
     459
    305460    // Set a hash of model attributes on the object, firing `"change"`. This is
    306461    // the core primitive operation of a model, updating the data and notifying
    307462    // anyone who needs to know about the change in state. The heart of the beast.
    308463    set: function(key, val, options) {
    309       var attr, attrs, unset, changes, silent, changing, prev, current;
    310464      if (key == null) return this;
    311465
    312466      // Handle both `"key", value` and `{key: value}` -style arguments.
     467      var attrs;
    313468      if (typeof key === 'object') {
    314469        attrs = key;
     
    324479
    325480      // Extract attributes and options.
    326       unset           = options.unset;
    327       silent          = options.silent;
    328       changes         = [];
    329       changing        = this._changing;
    330       this._changing  = true;
     481      var unset      = options.unset;
     482      var silent     = options.silent;
     483      var changes    = [];
     484      var changing   = this._changing;
     485      this._changing = true;
    331486
    332487      if (!changing) {
     
    334489        this.changed = {};
    335490      }
    336       current = this.attributes, prev = this._previousAttributes;
    337 
    338       // Check for changes of `id`.
    339       if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
     491
     492      var current = this.attributes;
     493      var changed = this.changed;
     494      var prev    = this._previousAttributes;
    340495
    341496      // For each `set` attribute, update or delete the current value.
    342       for (attr in attrs) {
     497      for (var attr in attrs) {
    343498        val = attrs[attr];
    344499        if (!_.isEqual(current[attr], val)) changes.push(attr);
    345500        if (!_.isEqual(prev[attr], val)) {
    346           this.changed[attr] = val;
     501          changed[attr] = val;
    347502        } else {
    348           delete this.changed[attr];
     503          delete changed[attr];
    349504        }
    350505        unset ? delete current[attr] : current[attr] = val;
    351506      }
     507
     508      // Update the `id`.
     509      this.id = this.get(this.idAttribute);
    352510
    353511      // Trigger all relevant attribute changes.
    354512      if (!silent) {
    355513        if (changes.length) this._pending = options;
    356         for (var i = 0, l = changes.length; i < l; i++) {
     514        for (var i = 0; i < changes.length; i++) {
    357515          this.trigger('change:' + changes[i], this, current[changes[i]], options);
    358516        }
     
    402560    changedAttributes: function(diff) {
    403561      if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
    404       var val, changed = false;
    405562      var old = this._changing ? this._previousAttributes : this.attributes;
     563      var changed = {};
    406564      for (var attr in diff) {
    407         if (_.isEqual(old[attr], (val = diff[attr]))) continue;
    408         (changed || (changed = {}))[attr] = val;
    409       }
    410       return changed;
     565        var val = diff[attr];
     566        if (_.isEqual(old[attr], val)) continue;
     567        changed[attr] = val;
     568      }
     569      return _.size(changed) ? changed : false;
    411570    },
    412571
     
    424583    },
    425584
    426     // Fetch the model from the server. If the server's representation of the
    427     // model differs from its current attributes, they will be overridden,
    428     // triggering a `"change"` event.
     585    // Fetch the model from the server, merging the response with the model's
     586    // local attributes. Any changed attributes will trigger a "change" event.
    429587    fetch: function(options) {
    430       options = options ? _.clone(options) : {};
    431       if (options.parse === void 0) options.parse = true;
     588      options = _.extend({parse: true}, options);
    432589      var model = this;
    433590      var success = options.success;
    434591      options.success = function(resp) {
    435         if (!model.set(model.parse(resp, options), options)) return false;
    436         if (success) success(model, resp, options);
     592        var serverAttrs = options.parse ? model.parse(resp, options) : resp;
     593        if (!model.set(serverAttrs, options)) return false;
     594        if (success) success.call(options.context, model, resp, options);
    437595        model.trigger('sync', model, resp, options);
    438596      };
     
    445603    // state will be `set` again.
    446604    save: function(key, val, options) {
    447       var attrs, method, xhr, attributes = this.attributes;
    448 
    449605      // Handle both `"key", value` and `{key: value}` -style arguments.
     606      var attrs;
    450607      if (key == null || typeof key === 'object') {
    451608        attrs = key;
     
    455612      }
    456613
    457       options = _.extend({validate: true}, options);
     614      options = _.extend({validate: true, parse: true}, options);
     615      var wait = options.wait;
    458616
    459617      // If we're not waiting and attributes exist, save acts as
    460618      // `set(attr).save(null, opts)` with validation. Otherwise, check if
    461619      // the model will be valid when the attributes, if any, are set.
    462       if (attrs && !options.wait) {
     620      if (attrs && !wait) {
    463621        if (!this.set(attrs, options)) return false;
    464622      } else {
     
    466624      }
    467625
    468       // Set temporary attributes if `{wait: true}`.
    469       if (attrs && options.wait) {
    470         this.attributes = _.extend({}, attributes, attrs);
    471       }
    472 
    473626      // After a successful server-side save, the client is (optionally)
    474627      // updated with the server-side state.
    475       if (options.parse === void 0) options.parse = true;
    476628      var model = this;
    477629      var success = options.success;
     630      var attributes = this.attributes;
    478631      options.success = function(resp) {
    479632        // Ensure attributes are restored during synchronous saves.
    480633        model.attributes = attributes;
    481         var serverAttrs = model.parse(resp, options);
    482         if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
    483         if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
    484           return false;
    485         }
    486         if (success) success(model, resp, options);
     634        var serverAttrs = options.parse ? model.parse(resp, options) : resp;
     635        if (wait) serverAttrs = _.extend({}, attrs, serverAttrs);
     636        if (serverAttrs && !model.set(serverAttrs, options)) return false;
     637        if (success) success.call(options.context, model, resp, options);
    487638        model.trigger('sync', model, resp, options);
    488639      };
    489640      wrapError(this, options);
    490641
    491       method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
    492       if (method === 'patch') options.attrs = attrs;
    493       xhr = this.sync(method, this, options);
     642      // Set temporary attributes if `{wait: true}` to properly find new ids.
     643      if (attrs && wait) this.attributes = _.extend({}, attributes, attrs);
     644
     645      var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
     646      if (method === 'patch' && !options.attrs) options.attrs = attrs;
     647      var xhr = this.sync(method, this, options);
    494648
    495649      // Restore attributes.
    496       if (attrs && options.wait) this.attributes = attributes;
     650      this.attributes = attributes;
    497651
    498652      return xhr;
     
    506660      var model = this;
    507661      var success = options.success;
     662      var wait = options.wait;
    508663
    509664      var destroy = function() {
     665        model.stopListening();
    510666        model.trigger('destroy', model, model.collection, options);
    511667      };
    512668
    513669      options.success = function(resp) {
    514         if (options.wait || model.isNew()) destroy();
    515         if (success) success(model, resp, options);
     670        if (wait) destroy();
     671        if (success) success.call(options.context, model, resp, options);
    516672        if (!model.isNew()) model.trigger('sync', model, resp, options);
    517673      };
    518674
     675      var xhr = false;
    519676      if (this.isNew()) {
    520         options.success();
    521         return false;
    522       }
    523       wrapError(this, options);
    524 
    525       var xhr = this.sync('delete', this, options);
    526       if (!options.wait) destroy();
     677        _.defer(options.success);
     678      } else {
     679        wrapError(this, options);
     680        xhr = this.sync('delete', this, options);
     681      }
     682      if (!wait) destroy();
    527683      return xhr;
    528684    },
     
    537693        urlError();
    538694      if (this.isNew()) return base;
    539       return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
     695      var id = this.get(this.idAttribute);
     696      return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
    540697    },
    541698
     
    558715    // Check if the model is currently in a valid state.
    559716    isValid: function(options) {
    560       return this._validate({}, _.extend(options || {}, { validate: true }));
     717      return this._validate({}, _.defaults({validate: true}, options));
    561718    },
    562719
     
    574731  });
    575732
    576   // Underscore methods that we want to implement on the Model.
    577   var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
     733  // Underscore methods that we want to implement on the Model, mapped to the
     734  // number of arguments they take.
     735  var modelMethods = { keys: 1, values: 1, pairs: 1, invert: 1, pick: 0,
     736      omit: 0, chain: 1, isEmpty: 1 };
    578737
    579738  // Mix in each Underscore method as a proxy to `Model#attributes`.
    580   _.each(modelMethods, function(method) {
    581     Model.prototype[method] = function() {
    582       var args = slice.call(arguments);
    583       args.unshift(this.attributes);
    584       return _[method].apply(_, args);
    585     };
    586   });
     739  addUnderscoreMethods(Model, modelMethods, 'attributes');
    587740
    588741  // Backbone.Collection
     
    590743
    591744  // If models tend to represent a single row of data, a Backbone Collection is
    592   // more analagous to a table full of data ... or a small slice or page of that
     745  // more analogous to a table full of data ... or a small slice or page of that
    593746  // table, or a collection of rows that belong together for a particular reason
    594747  // -- all of the messages in this particular folder, all of the documents
     
    612765  var addOptions = {add: true, remove: false};
    613766
     767  // Splices `insert` into `array` at index `at`.
     768  var splice = function(array, insert, at) {
     769    at = Math.min(Math.max(at, 0), array.length);
     770    var tail = Array(array.length - at);
     771    var length = insert.length;
     772    for (var i = 0; i < tail.length; i++) tail[i] = array[i + at];
     773    for (i = 0; i < length; i++) array[i + at] = insert[i];
     774    for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
     775  };
     776
    614777  // Define the Collection's inheritable methods.
    615778  _.extend(Collection.prototype, Events, {
     
    626789    // models' attributes.
    627790    toJSON: function(options) {
    628       return this.map(function(model){ return model.toJSON(options); });
     791      return this.map(function(model) { return model.toJSON(options); });
    629792    },
    630793
     
    634797    },
    635798
    636     // Add a model, or list of models to the set.
     799    // Add a model, or list of models to the set. `models` may be Backbone
     800    // Models or raw JavaScript objects to be converted to Models, or any
     801    // combination of the two.
    637802    add: function(models, options) {
    638803      return this.set(models, _.extend({merge: false}, options, addOptions));
     
    641806    // Remove a model, or a list of models from the set.
    642807    remove: function(models, options) {
     808      options = _.extend({}, options);
    643809      var singular = !_.isArray(models);
    644810      models = singular ? [models] : _.clone(models);
    645       options || (options = {});
    646       var i, l, index, model;
    647       for (i = 0, l = models.length; i < l; i++) {
    648         model = models[i] = this.get(models[i]);
    649         if (!model) continue;
    650         delete this._byId[model.id];
    651         delete this._byId[model.cid];
    652         index = this.indexOf(model);
    653         this.models.splice(index, 1);
    654         this.length--;
    655         if (!options.silent) {
    656           options.index = index;
    657           model.trigger('remove', model, this, options);
    658         }
    659         this._removeReference(model, options);
    660       }
    661       return singular ? models[0] : models;
     811      var removed = this._removeModels(models, options);
     812      if (!options.silent && removed) this.trigger('update', this, options);
     813      return singular ? removed[0] : removed;
    662814    },
    663815
     
    667819    // the core operation for updating the data contained by the collection.
    668820    set: function(models, options) {
     821      if (models == null) return;
     822
    669823      options = _.defaults({}, options, setOptions);
    670       if (options.parse) models = this.parse(models, options);
     824      if (options.parse && !this._isModel(models)) models = this.parse(models, options);
     825
    671826      var singular = !_.isArray(models);
    672       models = singular ? (models ? [models] : []) : _.clone(models);
    673       var i, l, id, model, attrs, existing, sort;
     827      models = singular ? [models] : models.slice();
     828
    674829      var at = options.at;
    675       var targetModel = this.model;
     830      if (at != null) at = +at;
     831      if (at < 0) at += this.length + 1;
     832
     833      var set = [];
     834      var toAdd = [];
     835      var toRemove = [];
     836      var modelMap = {};
     837
     838      var add = options.add;
     839      var merge = options.merge;
     840      var remove = options.remove;
     841
     842      var sort = false;
    676843      var sortable = this.comparator && (at == null) && options.sort !== false;
    677844      var sortAttr = _.isString(this.comparator) ? this.comparator : null;
    678       var toAdd = [], toRemove = [], modelMap = {};
    679       var add = options.add, merge = options.merge, remove = options.remove;
    680       var order = !sortable && add && remove ? [] : false;
    681845
    682846      // Turn bare objects into model references, and prevent invalid models
    683847      // from being added.
    684       for (i = 0, l = models.length; i < l; i++) {
    685         attrs = models[i] || {};
    686         if (attrs instanceof Model) {
    687           id = model = attrs;
    688         } else {
    689           id = attrs[targetModel.prototype.idAttribute || 'id'];
    690         }
     848      var model;
     849      for (var i = 0; i < models.length; i++) {
     850        model = models[i];
    691851
    692852        // If a duplicate is found, prevent it from being added and
    693853        // optionally merge it into the existing model.
    694         if (existing = this.get(id)) {
    695           if (remove) modelMap[existing.cid] = true;
    696           if (merge) {
    697             attrs = attrs === model ? model.attributes : attrs;
     854        var existing = this.get(model);
     855        if (existing) {
     856          if (merge && model !== existing) {
     857            var attrs = this._isModel(model) ? model.attributes : model;
    698858            if (options.parse) attrs = existing.parse(attrs, options);
    699859            existing.set(attrs, options);
    700             if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
     860            if (sortable && !sort) sort = existing.hasChanged(sortAttr);
     861          }
     862          if (!modelMap[existing.cid]) {
     863            modelMap[existing.cid] = true;
     864            set.push(existing);
    701865          }
    702866          models[i] = existing;
     
    704868        // If this is a new, valid model, push it to the `toAdd` list.
    705869        } else if (add) {
    706           model = models[i] = this._prepareModel(attrs, options);
    707           if (!model) continue;
    708           toAdd.push(model);
    709           this._addReference(model, options);
    710         }
    711 
    712         // Do not add multiple models with the same `id`.
    713         model = existing || model;
    714         if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
    715         modelMap[model.id] = true;
    716       }
    717 
    718       // Remove nonexistent models if appropriate.
    719       if (remove) {
    720         for (i = 0, l = this.length; i < l; ++i) {
    721           if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
    722         }
    723         if (toRemove.length) this.remove(toRemove, options);
    724       }
    725 
    726       // See if sorting is needed, update `length` and splice in new models.
    727       if (toAdd.length || (order && order.length)) {
    728         if (sortable) sort = true;
    729         this.length += toAdd.length;
    730         if (at != null) {
    731           for (i = 0, l = toAdd.length; i < l; i++) {
    732             this.models.splice(at + i, 0, toAdd[i]);
    733           }
    734         } else {
    735           if (order) this.models.length = 0;
    736           var orderedModels = order || toAdd;
    737           for (i = 0, l = orderedModels.length; i < l; i++) {
    738             this.models.push(orderedModels[i]);
     870          model = models[i] = this._prepareModel(model, options);
     871          if (model) {
     872            toAdd.push(model);
     873            this._addReference(model, options);
     874            modelMap[model.cid] = true;
     875            set.push(model);
    739876          }
    740877        }
    741878      }
    742879
     880      // Remove stale models.
     881      if (remove) {
     882        for (i = 0; i < this.length; i++) {
     883          model = this.models[i];
     884          if (!modelMap[model.cid]) toRemove.push(model);
     885        }
     886        if (toRemove.length) this._removeModels(toRemove, options);
     887      }
     888
     889      // See if sorting is needed, update `length` and splice in new models.
     890      var orderChanged = false;
     891      var replace = !sortable && add && remove;
     892      if (set.length && replace) {
     893        orderChanged = this.length != set.length || _.some(this.models, function(model, index) {
     894          return model !== set[index];
     895        });
     896        this.models.length = 0;
     897        splice(this.models, set, 0);
     898        this.length = this.models.length;
     899      } else if (toAdd.length) {
     900        if (sortable) sort = true;
     901        splice(this.models, toAdd, at == null ? this.length : at);
     902        this.length = this.models.length;
     903      }
     904
    743905      // Silently sort the collection if appropriate.
    744906      if (sort) this.sort({silent: true});
     
    746908      // Unless silenced, it's time to fire all appropriate add/sort events.
    747909      if (!options.silent) {
    748         for (i = 0, l = toAdd.length; i < l; i++) {
    749           (model = toAdd[i]).trigger('add', model, this, options);
     910        for (i = 0; i < toAdd.length; i++) {
     911          if (at != null) options.index = at + i;
     912          model = toAdd[i];
     913          model.trigger('add', model, this, options);
    750914        }
    751         if (sort || (order && order.length)) this.trigger('sort', this, options);
     915        if (sort || orderChanged) this.trigger('sort', this, options);
     916        if (toAdd.length || toRemove.length) this.trigger('update', this, options);
    752917      }
    753918
     
    761926    // Useful for bulk operations and optimizations.
    762927    reset: function(models, options) {
    763       options || (options = {});
    764       for (var i = 0, l = this.models.length; i < l; i++) {
     928      options = options ? _.clone(options) : {};
     929      for (var i = 0; i < this.models.length; i++) {
    765930        this._removeReference(this.models[i], options);
    766931      }
     
    780945    pop: function(options) {
    781946      var model = this.at(this.length - 1);
    782       this.remove(model, options);
    783       return model;
     947      return this.remove(model, options);
    784948    },
    785949
     
    792956    shift: function(options) {
    793957      var model = this.at(0);
    794       this.remove(model, options);
    795       return model;
     958      return this.remove(model, options);
    796959    },
    797960
     
    804967    get: function(obj) {
    805968      if (obj == null) return void 0;
    806       return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
     969      var id = this.modelId(this._isModel(obj) ? obj.attributes : obj);
     970      return this._byId[obj] || this._byId[id] || this._byId[obj.cid];
    807971    },
    808972
    809973    // Get the model at the given index.
    810974    at: function(index) {
     975      if (index < 0) index += this.length;
    811976      return this.models[index];
    812977    },
     
    815980    // `filter`.
    816981    where: function(attrs, first) {
    817       if (_.isEmpty(attrs)) return first ? void 0 : [];
    818       return this[first ? 'find' : 'filter'](function(model) {
    819         for (var key in attrs) {
    820           if (attrs[key] !== model.get(key)) return false;
    821         }
    822         return true;
    823       });
     982      return this[first ? 'find' : 'filter'](attrs);
    824983    },
    825984
     
    834993    // is added.
    835994    sort: function(options) {
    836       if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
     995      var comparator = this.comparator;
     996      if (!comparator) throw new Error('Cannot sort a set without a comparator');
    837997      options || (options = {});
    838998
     999      var length = comparator.length;
     1000      if (_.isFunction(comparator)) comparator = _.bind(comparator, this);
     1001
    8391002      // Run sort based on type of `comparator`.
    840       if (_.isString(this.comparator) || this.comparator.length === 1) {
    841         this.models = this.sortBy(this.comparator, this);
     1003      if (length === 1 || _.isString(comparator)) {
     1004        this.models = this.sortBy(comparator);
    8421005      } else {
    843         this.models.sort(_.bind(this.comparator, this));
    844       }
    845 
     1006        this.models.sort(comparator);
     1007      }
    8461008      if (!options.silent) this.trigger('sort', this, options);
    8471009      return this;
     
    8571019    // data will be passed through the `reset` method instead of `set`.
    8581020    fetch: function(options) {
    859       options = options ? _.clone(options) : {};
    860       if (options.parse === void 0) options.parse = true;
     1021      options = _.extend({parse: true}, options);
    8611022      var success = options.success;
    8621023      var collection = this;
     
    8641025        var method = options.reset ? 'reset' : 'set';
    8651026        collection[method](resp, options);
    866         if (success) success(collection, resp, options);
     1027        if (success) success.call(options.context, collection, resp, options);
    8671028        collection.trigger('sync', collection, resp, options);
    8681029      };
     
    8761037    create: function(model, options) {
    8771038      options = options ? _.clone(options) : {};
    878       if (!(model = this._prepareModel(model, options))) return false;
    879       if (!options.wait) this.add(model, options);
     1039      var wait = options.wait;
     1040      model = this._prepareModel(model, options);
     1041      if (!model) return false;
     1042      if (!wait) this.add(model, options);
    8801043      var collection = this;
    8811044      var success = options.success;
    882       options.success = function(model, resp) {
    883         if (options.wait) collection.add(model, options);
    884         if (success) success(model, resp, options);
     1045      options.success = function(model, resp, callbackOpts) {
     1046        if (wait) collection.add(model, callbackOpts);
     1047        if (success) success.call(callbackOpts.context, model, resp, callbackOpts);
    8851048      };
    8861049      model.save(null, options);
     
    8961059    // Create a new collection with an identical list of models as this one.
    8971060    clone: function() {
    898       return new this.constructor(this.models);
     1061      return new this.constructor(this.models, {
     1062        model: this.model,
     1063        comparator: this.comparator
     1064      });
     1065    },
     1066
     1067    // Define how to uniquely identify models in the collection.
     1068    modelId: function (attrs) {
     1069      return attrs[this.model.prototype.idAttribute || 'id'];
    8991070    },
    9001071
     
    9101081    // collection.
    9111082    _prepareModel: function(attrs, options) {
    912       if (attrs instanceof Model) return attrs;
     1083      if (this._isModel(attrs)) {
     1084        if (!attrs.collection) attrs.collection = this;
     1085        return attrs;
     1086      }
    9131087      options = options ? _.clone(options) : {};
    9141088      options.collection = this;
     
    9191093    },
    9201094
     1095    // Internal method called by both remove and set.
     1096    _removeModels: function(models, options) {
     1097      var removed = [];
     1098      for (var i = 0; i < models.length; i++) {
     1099        var model = this.get(models[i]);
     1100        if (!model) continue;
     1101
     1102        var index = this.indexOf(model);
     1103        this.models.splice(index, 1);
     1104        this.length--;
     1105
     1106        if (!options.silent) {
     1107          options.index = index;
     1108          model.trigger('remove', model, this, options);
     1109        }
     1110
     1111        removed.push(model);
     1112        this._removeReference(model, options);
     1113      }
     1114      return removed.length ? removed : false;
     1115    },
     1116
     1117    // Method for checking whether an object should be considered a model for
     1118    // the purposes of adding to the collection.
     1119    _isModel: function (model) {
     1120      return model instanceof Model;
     1121    },
     1122
    9211123    // Internal method to create a model's ties to a collection.
    9221124    _addReference: function(model, options) {
    9231125      this._byId[model.cid] = model;
    924       if (model.id != null) this._byId[model.id] = model;
    925       if (!model.collection) model.collection = this;
     1126      var id = this.modelId(model.attributes);
     1127      if (id != null) this._byId[id] = model;
    9261128      model.on('all', this._onModelEvent, this);
    9271129    },
     
    9291131    // Internal method to sever a model's ties to a collection.
    9301132    _removeReference: function(model, options) {
     1133      delete this._byId[model.cid];
     1134      var id = this.modelId(model.attributes);
     1135      if (id != null) delete this._byId[id];
    9311136      if (this === model.collection) delete model.collection;
    9321137      model.off('all', this._onModelEvent, this);
     
    9401145      if ((event === 'add' || event === 'remove') && collection !== this) return;
    9411146      if (event === 'destroy') this.remove(model, options);
    942       if (model && event === 'change:' + model.idAttribute) {
    943         delete this._byId[model.previous(model.idAttribute)];
    944         if (model.id != null) this._byId[model.id] = model;
     1147      if (event === 'change') {
     1148        var prevId = this.modelId(model.previousAttributes());
     1149        var id = this.modelId(model.attributes);
     1150        if (prevId !== id) {
     1151          if (prevId != null) delete this._byId[prevId];
     1152          if (id != null) this._byId[id] = model;
     1153        }
    9451154      }
    9461155      this.trigger.apply(this, arguments);
     
    9521161  // 90% of the core usefulness of Backbone Collections is actually implemented
    9531162  // right here:
    954   var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
    955     'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
    956     'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
    957     'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
    958     'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
    959     'lastIndexOf', 'isEmpty', 'chain', 'sample'];
     1163  var collectionMethods = { forEach: 3, each: 3, map: 3, collect: 3, reduce: 4,
     1164      foldl: 4, inject: 4, reduceRight: 4, foldr: 4, find: 3, detect: 3, filter: 3,
     1165      select: 3, reject: 3, every: 3, all: 3, some: 3, any: 3, include: 3, includes: 3,
     1166      contains: 3, invoke: 0, max: 3, min: 3, toArray: 1, size: 1, first: 3,
     1167      head: 3, take: 3, initial: 3, rest: 3, tail: 3, drop: 3, last: 3,
     1168      without: 0, difference: 0, indexOf: 3, shuffle: 1, lastIndexOf: 3,
     1169      isEmpty: 1, chain: 1, sample: 3, partition: 3, groupBy: 3, countBy: 3,
     1170      sortBy: 3, indexBy: 3};
    9601171
    9611172  // Mix in each Underscore method as a proxy to `Collection#models`.
    962   _.each(methods, function(method) {
    963     Collection.prototype[method] = function() {
    964       var args = slice.call(arguments);
    965       args.unshift(this.models);
    966       return _[method].apply(_, args);
    967     };
    968   });
    969 
    970   // Underscore methods that take a property name as an argument.
    971   var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
    972 
    973   // Use attributes instead of properties.
    974   _.each(attributeMethods, function(method) {
    975     Collection.prototype[method] = function(value, context) {
    976       var iterator = _.isFunction(value) ? value : function(model) {
    977         return model.get(value);
    978       };
    979       return _[method](this.models, iterator, context);
    980     };
    981   });
     1173  addUnderscoreMethods(Collection, collectionMethods, 'models');
    9821174
    9831175  // Backbone.View
     
    9961188  var View = Backbone.View = function(options) {
    9971189    this.cid = _.uniqueId('view');
    998     options || (options = {});
    9991190    _.extend(this, _.pick(options, viewOptions));
    10001191    this._ensureElement();
    10011192    this.initialize.apply(this, arguments);
    1002     this.delegateEvents();
    10031193  };
    10041194
     
    10061196  var delegateEventSplitter = /^(\S+)\s*(.*)$/;
    10071197
    1008   // List of view options to be merged as properties.
     1198  // List of view options to be set as properties.
    10091199  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
    10101200
     
    10351225    // applicable Backbone.Events listeners.
    10361226    remove: function() {
    1037       this.$el.remove();
     1227      this._removeElement();
    10381228      this.stopListening();
    10391229      return this;
    10401230    },
    10411231
    1042     // Change the view's element (`this.el` property), including event
    1043     // re-delegation.
    1044     setElement: function(element, delegate) {
    1045       if (this.$el) this.undelegateEvents();
    1046       this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
     1232    // Remove this view's element from the document and all event listeners
     1233    // attached to it. Exposed for subclasses using an alternative DOM
     1234    // manipulation API.
     1235    _removeElement: function() {
     1236      this.$el.remove();
     1237    },
     1238
     1239    // Change the view's element (`this.el` property) and re-delegate the
     1240    // view's events on the new element.
     1241    setElement: function(element) {
     1242      this.undelegateEvents();
     1243      this._setElement(element);
     1244      this.delegateEvents();
     1245      return this;
     1246    },
     1247
     1248    // Creates the `this.el` and `this.$el` references for this view using the
     1249    // given `el`. `el` can be a CSS selector or an HTML string, a jQuery
     1250    // context or an element. Subclasses can override this to utilize an
     1251    // alternative DOM manipulation API and are only required to set the
     1252    // `this.el` property.
     1253    _setElement: function(el) {
     1254      this.$el = el instanceof Backbone.$ ? el : Backbone.$(el);
    10471255      this.el = this.$el[0];
    1048       if (delegate !== false) this.delegateEvents();
    1049       return this;
    10501256    },
    10511257
     
    10631269    // Uses event delegation for efficiency.
    10641270    // Omitting the selector binds the event to `this.el`.
    1065     // This only works for delegate-able events: not `focus`, `blur`, and
    1066     // not `change`, `submit`, and `reset` in Internet Explorer.
    10671271    delegateEvents: function(events) {
    1068       if (!(events || (events = _.result(this, 'events')))) return this;
     1272      events || (events = _.result(this, 'events'));
     1273      if (!events) return this;
    10691274      this.undelegateEvents();
    10701275      for (var key in events) {
    10711276        var method = events[key];
    1072         if (!_.isFunction(method)) method = this[events[key]];
     1277        if (!_.isFunction(method)) method = this[method];
    10731278        if (!method) continue;
    1074 
    10751279        var match = key.match(delegateEventSplitter);
    1076         var eventName = match[1], selector = match[2];
    1077         method = _.bind(method, this);
    1078         eventName += '.delegateEvents' + this.cid;
    1079         if (selector === '') {
    1080           this.$el.on(eventName, method);
    1081         } else {
    1082           this.$el.on(eventName, selector, method);
    1083         }
     1280        this.delegate(match[1], match[2], _.bind(method, this));
    10841281      }
    10851282      return this;
    10861283    },
    10871284
    1088     // Clears all callbacks previously bound to the view with `delegateEvents`.
     1285    // Add a single event listener to the view's element (or a child element
     1286    // using `selector`). This only works for delegate-able events: not `focus`,
     1287    // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
     1288    delegate: function(eventName, selector, listener) {
     1289      this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
     1290      return this;
     1291    },
     1292
     1293    // Clears all callbacks previously bound to the view by `delegateEvents`.
    10891294    // You usually don't need to use this, but may wish to if you have multiple
    10901295    // Backbone views attached to the same DOM element.
    10911296    undelegateEvents: function() {
    1092       this.$el.off('.delegateEvents' + this.cid);
     1297      if (this.$el) this.$el.off('.delegateEvents' + this.cid);
    10931298      return this;
     1299    },
     1300
     1301    // A finer-grained `undelegateEvents` for removing a single delegated event.
     1302    // `selector` and `listener` are both optional.
     1303    undelegate: function(eventName, selector, listener) {
     1304      this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
     1305      return this;
     1306    },
     1307
     1308    // Produces a DOM element to be assigned to your view. Exposed for
     1309    // subclasses using an alternative DOM manipulation API.
     1310    _createElement: function(tagName) {
     1311      return document.createElement(tagName);
    10941312    },
    10951313
     
    11031321        if (this.id) attrs.id = _.result(this, 'id');
    11041322        if (this.className) attrs['class'] = _.result(this, 'className');
    1105         var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
    1106         this.setElement($el, false);
     1323        this.setElement(this._createElement(_.result(this, 'tagName')));
     1324        this._setAttributes(attrs);
    11071325      } else {
    1108         this.setElement(_.result(this, 'el'), false);
    1109       }
     1326        this.setElement(_.result(this, 'el'));
     1327      }
     1328    },
     1329
     1330    // Set attributes from a hash on this view's element.  Exposed for
     1331    // subclasses using an alternative DOM manipulation API.
     1332    _setAttributes: function(attributes) {
     1333      this.$el.attr(attributes);
    11101334    }
    11111335
     
    11761400    }
    11771401
    1178     // If we're sending a `PATCH` request, and we're in an old Internet Explorer
    1179     // that still has ActiveX enabled by default, override jQuery to use that
    1180     // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
    1181     if (params.type === 'PATCH' && noXhrPatch) {
    1182       params.xhr = function() {
    1183         return new ActiveXObject("Microsoft.XMLHTTP");
    1184       };
    1185     }
     1402    // Pass along `textStatus` and `errorThrown` from jQuery.
     1403    var error = options.error;
     1404    options.error = function(xhr, textStatus, errorThrown) {
     1405      options.textStatus = textStatus;
     1406      options.errorThrown = errorThrown;
     1407      if (error) error.call(options.context, xhr, textStatus, errorThrown);
     1408    };
    11861409
    11871410    // Make the request, allowing the user to override any Ajax options.
     
    11901413    return xhr;
    11911414  };
    1192 
    1193   var noXhrPatch =
    1194     typeof window !== 'undefined' && !!window.ActiveXObject &&
    1195       !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
    11961415
    11971416  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
     
    12521471      Backbone.history.route(route, function(fragment) {
    12531472        var args = router._extractParameters(route, fragment);
    1254         router.execute(callback, args);
    1255         router.trigger.apply(router, ['route:' + name].concat(args));
    1256         router.trigger('route', name, args);
    1257         Backbone.history.trigger('route', router, name, args);
     1473        if (router.execute(callback, args, name) !== false) {
     1474          router.trigger.apply(router, ['route:' + name].concat(args));
     1475          router.trigger('route', name, args);
     1476          Backbone.history.trigger('route', router, name, args);
     1477        }
    12581478      });
    12591479      return this;
     
    12621482    // Execute a route handler with the provided parameters.  This is an
    12631483    // excellent place to do pre-route setup or post-route cleanup.
    1264     execute: function(callback, args) {
     1484    execute: function(callback, args, name) {
    12651485      if (callback) callback.apply(this, args);
    12661486    },
     
    13201540  var History = Backbone.History = function() {
    13211541    this.handlers = [];
    1322     _.bindAll(this, 'checkUrl');
     1542    this.checkUrl = _.bind(this.checkUrl, this);
    13231543
    13241544    // Ensure that `History` can be used outside of the browser.
     
    13351555  var rootStripper = /^\/+|\/+$/g;
    13361556
    1337   // Cached regex for detecting MSIE.
    1338   var isExplorer = /msie [\w.]+/;
    1339 
    1340   // Cached regex for removing a trailing slash.
    1341   var trailingSlash = /\/$/;
    1342 
    13431557  // Cached regex for stripping urls of hash.
    13441558  var pathStripper = /#.*$/;
     
    13561570    // Are we at the app root?
    13571571    atRoot: function() {
    1358       return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
     1572      var path = this.location.pathname.replace(/[^\/]$/, '$&/');
     1573      return path === this.root && !this.getSearch();
     1574    },
     1575
     1576    // Does the pathname match the root?
     1577    matchRoot: function() {
     1578      var path = this.decodeFragment(this.location.pathname);
     1579      var root = path.slice(0, this.root.length - 1) + '/';
     1580      return root === this.root;
     1581    },
     1582
     1583    // Unicode characters in `location.pathname` are percent encoded so they're
     1584    // decoded for comparison. `%25` should not be decoded since it may be part
     1585    // of an encoded parameter.
     1586    decodeFragment: function(fragment) {
     1587      return decodeURI(fragment.replace(/%25/g, '%2525'));
     1588    },
     1589
     1590    // In IE6, the hash fragment and search params are incorrect if the
     1591    // fragment contains `?`.
     1592    getSearch: function() {
     1593      var match = this.location.href.replace(/#.*/, '').match(/\?.+/);
     1594      return match ? match[0] : '';
    13591595    },
    13601596
     
    13661602    },
    13671603
    1368     // Get the cross-browser normalized URL fragment, either from the URL,
    1369     // the hash, or the override.
    1370     getFragment: function(fragment, forcePushState) {
     1604    // Get the pathname and search params, without the root.
     1605    getPath: function() {
     1606      var path = this.decodeFragment(
     1607        this.location.pathname + this.getSearch()
     1608      ).slice(this.root.length - 1);
     1609      return path.charAt(0) === '/' ? path.slice(1) : path;
     1610    },
     1611
     1612    // Get the cross-browser normalized URL fragment from the path or hash.
     1613    getFragment: function(fragment) {
    13711614      if (fragment == null) {
    1372         if (this._hasPushState || !this._wantsHashChange || forcePushState) {
    1373           fragment = decodeURI(this.location.pathname + this.location.search);
    1374           var root = this.root.replace(trailingSlash, '');
    1375           if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
     1615        if (this._usePushState || !this._wantsHashChange) {
     1616          fragment = this.getPath();
    13761617        } else {
    13771618          fragment = this.getHash();
     
    13841625    // an existing route, and `false` otherwise.
    13851626    start: function(options) {
    1386       if (History.started) throw new Error("Backbone.history has already been started");
     1627      if (History.started) throw new Error('Backbone.history has already been started');
    13871628      History.started = true;
    13881629
     
    13921633      this.root             = this.options.root;
    13931634      this._wantsHashChange = this.options.hashChange !== false;
     1635      this._hasHashChange   = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7);
     1636      this._useHashChange   = this._wantsHashChange && this._hasHashChange;
    13941637      this._wantsPushState  = !!this.options.pushState;
    1395       this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
    1396       var fragment          = this.getFragment();
    1397       var docMode           = document.documentMode;
    1398       var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
     1638      this._hasPushState    = !!(this.history && this.history.pushState);
     1639      this._usePushState    = this._wantsPushState && this._hasPushState;
     1640      this.fragment         = this.getFragment();
    13991641
    14001642      // Normalize root to always include a leading and trailing slash.
    14011643      this.root = ('/' + this.root + '/').replace(rootStripper, '/');
    1402 
    1403       if (oldIE && this._wantsHashChange) {
    1404         var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
    1405         this.iframe = frame.hide().appendTo('body')[0].contentWindow;
    1406         this.navigate(fragment);
    1407       }
    1408 
    1409       // Depending on whether we're using pushState or hashes, and whether
    1410       // 'onhashchange' is supported, determine how we check the URL state.
    1411       if (this._hasPushState) {
    1412         Backbone.$(window).on('popstate', this.checkUrl);
    1413       } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
    1414         Backbone.$(window).on('hashchange', this.checkUrl);
    1415       } else if (this._wantsHashChange) {
    1416         this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
    1417       }
    1418 
    1419       // Determine if we need to change the base url, for a pushState link
    1420       // opened by a non-pushState browser.
    1421       this.fragment = fragment;
    1422       var loc = this.location;
    14231644
    14241645      // Transition from hashChange to pushState or vice versa if both are
     
    14291650        // browser, but we're currently in a browser that doesn't support it...
    14301651        if (!this._hasPushState && !this.atRoot()) {
    1431           this.fragment = this.getFragment(null, true);
    1432           this.location.replace(this.root + '#' + this.fragment);
     1652          var root = this.root.slice(0, -1) || '/';
     1653          this.location.replace(root + '#' + this.getPath());
    14331654          // Return immediately as browser will do redirect to new url
    14341655          return true;
     
    14361657        // Or if we've started out with a hash-based route, but we're currently
    14371658        // in a browser where it could be `pushState`-based instead...
    1438         } else if (this._hasPushState && this.atRoot() && loc.hash) {
    1439           this.fragment = this.getHash().replace(routeStripper, '');
    1440           this.history.replaceState({}, document.title, this.root + this.fragment);
     1659        } else if (this._hasPushState && this.atRoot()) {
     1660          this.navigate(this.getHash(), {replace: true});
    14411661        }
    14421662
     1663      }
     1664
     1665      // Proxy an iframe to handle location events if the browser doesn't
     1666      // support the `hashchange` event, HTML5 history, or the user wants
     1667      // `hashChange` but not `pushState`.
     1668      if (!this._hasHashChange && this._wantsHashChange && !this._usePushState) {
     1669        this.iframe = document.createElement('iframe');
     1670        this.iframe.src = 'javascript:0';
     1671        this.iframe.style.display = 'none';
     1672        this.iframe.tabIndex = -1;
     1673        var body = document.body;
     1674        // Using `appendChild` will throw on IE < 9 if the document is not ready.
     1675        var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow;
     1676        iWindow.document.open();
     1677        iWindow.document.close();
     1678        iWindow.location.hash = '#' + this.fragment;
     1679      }
     1680
     1681      // Add a cross-platform `addEventListener` shim for older browsers.
     1682      var addEventListener = window.addEventListener || function (eventName, listener) {
     1683        return attachEvent('on' + eventName, listener);
     1684      };
     1685
     1686      // Depending on whether we're using pushState or hashes, and whether
     1687      // 'onhashchange' is supported, determine how we check the URL state.
     1688      if (this._usePushState) {
     1689        addEventListener('popstate', this.checkUrl, false);
     1690      } else if (this._useHashChange && !this.iframe) {
     1691        addEventListener('hashchange', this.checkUrl, false);
     1692      } else if (this._wantsHashChange) {
     1693        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
    14431694      }
    14441695
     
    14491700    // but possibly useful for unit testing Routers.
    14501701    stop: function() {
    1451       Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
     1702      // Add a cross-platform `removeEventListener` shim for older browsers.
     1703      var removeEventListener = window.removeEventListener || function (eventName, listener) {
     1704        return detachEvent('on' + eventName, listener);
     1705      };
     1706
     1707      // Remove window listeners.
     1708      if (this._usePushState) {
     1709        removeEventListener('popstate', this.checkUrl, false);
     1710      } else if (this._useHashChange && !this.iframe) {
     1711        removeEventListener('hashchange', this.checkUrl, false);
     1712      }
     1713
     1714      // Clean up the iframe if necessary.
     1715      if (this.iframe) {
     1716        document.body.removeChild(this.iframe);
     1717        this.iframe = null;
     1718      }
     1719
     1720      // Some environments will throw when clearing an undefined interval.
    14521721      if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
    14531722      History.started = false;
     
    14641733    checkUrl: function(e) {
    14651734      var current = this.getFragment();
     1735
     1736      // If the user pressed the back button, the iframe's hash will have
     1737      // changed and we should use that for comparison.
    14661738      if (current === this.fragment && this.iframe) {
    1467         current = this.getFragment(this.getHash(this.iframe));
    1468       }
     1739        current = this.getHash(this.iframe.contentWindow);
     1740      }
     1741
    14691742      if (current === this.fragment) return false;
    14701743      if (this.iframe) this.navigate(current);
     
    14761749    // returns `false`.
    14771750    loadUrl: function(fragment) {
     1751      // If the root doesn't match, no routes can match either.
     1752      if (!this.matchRoot()) return false;
    14781753      fragment = this.fragment = this.getFragment(fragment);
    1479       return _.any(this.handlers, function(handler) {
     1754      return _.some(this.handlers, function(handler) {
    14801755        if (handler.route.test(fragment)) {
    14811756          handler.callback(fragment);
     
    14961771      if (!options || options === true) options = {trigger: !!options};
    14971772
    1498       var url = this.root + (fragment = this.getFragment(fragment || ''));
    1499 
    1500       // Strip the hash for matching.
    1501       fragment = fragment.replace(pathStripper, '');
     1773      // Normalize the fragment.
     1774      fragment = this.getFragment(fragment || '');
     1775
     1776      // Don't include a trailing slash on the root.
     1777      var root = this.root;
     1778      if (fragment === '' || fragment.charAt(0) === '?') {
     1779        root = root.slice(0, -1) || '/';
     1780      }
     1781      var url = root + fragment;
     1782
     1783      // Strip the hash and decode for matching.
     1784      fragment = this.decodeFragment(fragment.replace(pathStripper, ''));
    15021785
    15031786      if (this.fragment === fragment) return;
    15041787      this.fragment = fragment;
    15051788
    1506       // Don't include a trailing slash on the root.
    1507       if (fragment === '' && url !== '/') url = url.slice(0, -1);
    1508 
    15091789      // If pushState is available, we use it to set the fragment as a real URL.
    1510       if (this._hasPushState) {
     1790      if (this._usePushState) {
    15111791        this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
    15121792
     
    15151795      } else if (this._wantsHashChange) {
    15161796        this._updateHash(this.location, fragment, options.replace);
    1517         if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
     1797        if (this.iframe && (fragment !== this.getHash(this.iframe.contentWindow))) {
     1798          var iWindow = this.iframe.contentWindow;
     1799
    15181800          // Opening and closing the iframe tricks IE7 and earlier to push a
    15191801          // history entry on hash-tag change.  When replace is true, we don't
    15201802          // want this.
    1521           if(!options.replace) this.iframe.document.open().close();
    1522           this._updateHash(this.iframe.location, fragment, options.replace);
     1803          if (!options.replace) {
     1804            iWindow.document.open();
     1805            iWindow.document.close();
     1806          }
     1807
     1808          this._updateHash(iWindow.location, fragment, options.replace);
    15231809        }
    15241810
     
    15511837  // -------
    15521838
    1553   // Helper function to correctly set up the prototype chain, for subclasses.
     1839  // Helper function to correctly set up the prototype chain for subclasses.
    15541840  // Similar to `goog.inherits`, but uses a hash of prototype properties and
    15551841  // class properties to be extended.
     
    15601846    // The constructor function for the new subclass is either defined by you
    15611847    // (the "constructor" property in your `extend` definition), or defaulted
    1562     // by us to simply call the parent's constructor.
     1848    // by us to simply call the parent constructor.
    15631849    if (protoProps && _.has(protoProps, 'constructor')) {
    15641850      child = protoProps.constructor;
     
    15711857
    15721858    // Set the prototype chain to inherit from `parent`, without calling
    1573     // `parent`'s constructor function.
     1859    // `parent` constructor function.
    15741860    var Surrogate = function(){ this.constructor = child; };
    15751861    Surrogate.prototype = parent.prototype;
     
    15991885    var error = options.error;
    16001886    options.error = function(resp) {
    1601       if (error) error(model, resp, options);
     1887      if (error) error.call(options.context, model, resp, options);
    16021888      model.trigger('error', model, resp, options);
    16031889    };
  • trunk/src/wp-includes/js/backbone.min.js

    r27233 r36546  
    1 (function(t,e){if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,s){t.Backbone=e(t,s,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore");e(t,exports,i)}else{t.Backbone=e(t,{},t._,t.jQuery||t.Zepto||t.ender||t.$)}})(this,function(t,e,i,r){var s=t.Backbone;var n=[];var a=n.push;var o=n.slice;var h=n.splice;e.VERSION="1.1.2";e.$=r;e.noConflict=function(){t.Backbone=s;return this};e.emulateHTTP=false;e.emulateJSON=false;var u=e.Events={on:function(t,e,i){if(!c(this,"on",t,[e,i])||!e)return this;this._events||(this._events={});var r=this._events[t]||(this._events[t]=[]);r.push({callback:e,context:i,ctx:i||this});return this},once:function(t,e,r){if(!c(this,"once",t,[e,r])||!e)return this;var s=this;var n=i.once(function(){s.off(t,n);e.apply(this,arguments)});n._callback=e;return this.on(t,n,r)},off:function(t,e,r){var s,n,a,o,h,u,l,f;if(!this._events||!c(this,"off",t,[e,r]))return this;if(!t&&!e&&!r){this._events=void 0;return this}o=t?[t]:i.keys(this._events);for(h=0,u=o.length;h<u;h++){t=o[h];if(a=this._events[t]){this._events[t]=s=[];if(e||r){for(l=0,f=a.length;l<f;l++){n=a[l];if(e&&e!==n.callback&&e!==n.callback._callback||r&&r!==n.context){s.push(n)}}}if(!s.length)delete this._events[t]}}return this},trigger:function(t){if(!this._events)return this;var e=o.call(arguments,1);if(!c(this,"trigger",t,e))return this;var i=this._events[t];var r=this._events.all;if(i)f(i,e);if(r)f(r,arguments);return this},stopListening:function(t,e,r){var s=this._listeningTo;if(!s)return this;var n=!e&&!r;if(!r&&typeof e==="object")r=this;if(t)(s={})[t._listenId]=t;for(var a in s){t=s[a];t.off(e,r,this);if(n||i.isEmpty(t._events))delete this._listeningTo[a]}return this}};var l=/\s+/;var c=function(t,e,i,r){if(!i)return true;if(typeof i==="object"){for(var s in i){t[e].apply(t,[s,i[s]].concat(r))}return false}if(l.test(i)){var n=i.split(l);for(var a=0,o=n.length;a<o;a++){t[e].apply(t,[n[a]].concat(r))}return false}return true};var f=function(t,e){var i,r=-1,s=t.length,n=e[0],a=e[1],o=e[2];switch(e.length){case 0:while(++r<s)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<s)(i=t[r]).callback.call(i.ctx,n);return;case 2:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a);return;case 3:while(++r<s)(i=t[r]).callback.call(i.ctx,n,a,o);return;default:while(++r<s)(i=t[r]).callback.apply(i.ctx,e);return}};var d={listenTo:"on",listenToOnce:"once"};i.each(d,function(t,e){u[e]=function(e,r,s){var n=this._listeningTo||(this._listeningTo={});var a=e._listenId||(e._listenId=i.uniqueId("l"));n[a]=e;if(!s&&typeof r==="object")s=this;e[t](r,s,this);return this}});u.bind=u.on;u.unbind=u.off;i.extend(e,u);var p=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId("c");this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};r=i.defaults({},r,i.result(this,"defaults"));this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(p.prototype,u,{changed:null,validationError:null,idAttribute:"id",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},set:function(t,e,r){var s,n,a,o,h,u,l,c;if(t==null)return this;if(typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r||(r={});if(!this._validate(n,r))return false;a=r.unset;h=r.silent;o=[];u=this._changing;this._changing=true;if(!u){this._previousAttributes=i.clone(this.attributes);this.changed={}}c=this.attributes,l=this._previousAttributes;if(this.idAttribute in n)this.id=n[this.idAttribute];for(s in n){e=n[s];if(!i.isEqual(c[s],e))o.push(s);if(!i.isEqual(l[s],e)){this.changed[s]=e}else{delete this.changed[s]}a?delete c[s]:c[s]=e}if(!h){if(o.length)this._pending=r;for(var f=0,d=o.length;f<d;f++){this.trigger("change:"+o[f],this,c[o[f]],r)}}if(u)return this;if(!h){while(this._pending){r=this._pending;this._pending=false;this.trigger("change",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e,r=false;var s=this._changing?this._previousAttributes:this.attributes;for(var n in t){if(i.isEqual(s[n],e=t[n]))continue;(r||(r={}))[n]=e}return r},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=this;var r=t.success;t.success=function(i){if(!e.set(e.parse(i,t),t))return false;if(r)r(e,i,t);e.trigger("sync",e,i,t)};q(this,t);return this.sync("read",this,t)},save:function(t,e,r){var s,n,a,o=this.attributes;if(t==null||typeof t==="object"){s=t;r=e}else{(s={})[t]=e}r=i.extend({validate:true},r);if(s&&!r.wait){if(!this.set(s,r))return false}else{if(!this._validate(s,r))return false}if(s&&r.wait){this.attributes=i.extend({},o,s)}if(r.parse===void 0)r.parse=true;var h=this;var u=r.success;r.success=function(t){h.attributes=o;var e=h.parse(t,r);if(r.wait)e=i.extend(s||{},e);if(i.isObject(e)&&!h.set(e,r)){return false}if(u)u(h,t,r);h.trigger("sync",h,t,r)};q(this,r);n=this.isNew()?"create":r.patch?"patch":"update";if(n==="patch")r.attrs=s;a=this.sync(n,this,r);if(s&&r.wait)this.attributes=o;return a},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var s=function(){e.trigger("destroy",e,e.collection,t)};t.success=function(i){if(t.wait||e.isNew())s();if(r)r(e,i,t);if(!e.isNew())e.trigger("sync",e,i,t)};if(this.isNew()){t.success();return false}q(this,t);var n=this.sync("delete",this,t);if(!t.wait)s();return n},url:function(){var t=i.result(this,"urlRoot")||i.result(this.collection,"url")||M();if(this.isNew())return t;return t.replace(/([^\/])$/,"$1/")+encodeURIComponent(this.id)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.extend(t||{},{validate:true}))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger("invalid",this,r,i.extend(e,{validationError:r}));return false}});var v=["keys","values","pairs","invert","pick","omit"];i.each(v,function(t){p.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.attributes);return i[t].apply(i,e)}});var g=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var m={add:true,remove:true,merge:true};var y={add:true,remove:false};i.extend(g.prototype,u,{model:p,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,y))},remove:function(t,e){var r=!i.isArray(t);t=r?[t]:i.clone(t);e||(e={});var s,n,a,o;for(s=0,n=t.length;s<n;s++){o=t[s]=this.get(t[s]);if(!o)continue;delete this._byId[o.id];delete this._byId[o.cid];a=this.indexOf(o);this.models.splice(a,1);this.length--;if(!e.silent){e.index=a;o.trigger("remove",o,this,e)}this._removeReference(o,e)}return r?t[0]:t},set:function(t,e){e=i.defaults({},e,m);if(e.parse)t=this.parse(t,e);var r=!i.isArray(t);t=r?t?[t]:[]:i.clone(t);var s,n,a,o,h,u,l;var c=e.at;var f=this.model;var d=this.comparator&&c==null&&e.sort!==false;var v=i.isString(this.comparator)?this.comparator:null;var g=[],y=[],_={};var b=e.add,w=e.merge,x=e.remove;var E=!d&&b&&x?[]:false;for(s=0,n=t.length;s<n;s++){h=t[s]||{};if(h instanceof p){a=o=h}else{a=h[f.prototype.idAttribute||"id"]}if(u=this.get(a)){if(x)_[u.cid]=true;if(w){h=h===o?o.attributes:h;if(e.parse)h=u.parse(h,e);u.set(h,e);if(d&&!l&&u.hasChanged(v))l=true}t[s]=u}else if(b){o=t[s]=this._prepareModel(h,e);if(!o)continue;g.push(o);this._addReference(o,e)}o=u||o;if(E&&(o.isNew()||!_[o.id]))E.push(o);_[o.id]=true}if(x){for(s=0,n=this.length;s<n;++s){if(!_[(o=this.models[s]).cid])y.push(o)}if(y.length)this.remove(y,e)}if(g.length||E&&E.length){if(d)l=true;this.length+=g.length;if(c!=null){for(s=0,n=g.length;s<n;s++){this.models.splice(c+s,0,g[s])}}else{if(E)this.models.length=0;var k=E||g;for(s=0,n=k.length;s<n;s++){this.models.push(k[s])}}}if(l)this.sort({silent:true});if(!e.silent){for(s=0,n=g.length;s<n;s++){(o=g[s]).trigger("add",o,this,e)}if(l||E&&E.length)this.trigger("sort",this,e)}return r?t[0]:t},reset:function(t,e){e||(e={});for(var r=0,s=this.models.length;r<s;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);this.remove(e,t);return e},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);this.remove(e,t);return e},slice:function(){return o.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;return this._byId[t]||this._byId[t.id]||this._byId[t.cid]},at:function(t){return this.models[t]},where:function(t,e){if(i.isEmpty(t))return e?void 0:[];return this[e?"find":"filter"](function(e){for(var i in t){if(t[i]!==e.get(i))return false}return true})},findWhere:function(t){return this.where(t,true)},sort:function(t){if(!this.comparator)throw new Error("Cannot sort a set without a comparator");t||(t={});if(i.isString(this.comparator)||this.comparator.length===1){this.models=this.sortBy(this.comparator,this)}else{this.models.sort(i.bind(this.comparator,this))}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return i.invoke(this.models,"get",t)},fetch:function(t){t=t?i.clone(t):{};if(t.parse===void 0)t.parse=true;var e=t.success;var r=this;t.success=function(i){var s=t.reset?"reset":"set";r[s](i,t);if(e)e(r,i,t);r.trigger("sync",r,i,t)};q(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?i.clone(e):{};if(!(t=this._prepareModel(t,e)))return false;if(!e.wait)this.add(t,e);var r=this;var s=e.success;e.success=function(t,i){if(e.wait)r.add(t,e);if(s)s(t,i,e)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models)},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(t instanceof p)return t;e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger("invalid",this,r.validationError,e);return false},_addReference:function(t,e){this._byId[t.cid]=t;if(t.id!=null)this._byId[t.id]=t;if(!t.collection)t.collection=this;t.on("all",this._onModelEvent,this)},_removeReference:function(t,e){if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(e&&t==="change:"+e.idAttribute){delete this._byId[e.previous(e.idAttribute)];if(e.id!=null)this._byId[e.id]=e}this.trigger.apply(this,arguments)}});var _=["forEach","each","map","collect","reduce","foldl","inject","reduceRight","foldr","find","detect","filter","select","reject","every","all","some","any","include","contains","invoke","max","min","toArray","size","first","head","take","initial","rest","tail","drop","last","without","difference","indexOf","shuffle","lastIndexOf","isEmpty","chain","sample"];i.each(_,function(t){g.prototype[t]=function(){var e=o.call(arguments);e.unshift(this.models);return i[t].apply(i,e)}});var b=["groupBy","countBy","sortBy","indexBy"];i.each(b,function(t){g.prototype[t]=function(e,r){var s=i.isFunction(e)?e:function(t){return t.get(e)};return i[t](this.models,s,r)}});var w=e.View=function(t){this.cid=i.uniqueId("view");t||(t={});i.extend(this,i.pick(t,E));this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()};var x=/^(\S+)\s*(.*)$/;var E=["model","collection","el","id","attributes","className","tagName","events"];i.extend(w.prototype,u,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();this.stopListening();return this},setElement:function(t,i){if(this.$el)this.undelegateEvents();this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0];if(i!==false)this.delegateEvents();return this},delegateEvents:function(t){if(!(t||(t=i.result(this,"events"))))return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[t[e]];if(!r)continue;var s=e.match(x);var n=s[1],a=s[2];r=i.bind(r,this);n+=".delegateEvents"+this.cid;if(a===""){this.$el.on(n,r)}else{this.$el.on(n,a,r)}}return this},undelegateEvents:function(){this.$el.off(".delegateEvents"+this.cid);return this},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,"attributes"));if(this.id)t.id=i.result(this,"id");if(this.className)t["class"]=i.result(this,"className");var r=e.$("<"+i.result(this,"tagName")+">").attr(t);this.setElement(r,false)}else{this.setElement(i.result(this,"el"),false)}}});e.sync=function(t,r,s){var n=T[t];i.defaults(s||(s={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:n,dataType:"json"};if(!s.url){a.url=i.result(r,"url")||M()}if(s.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(s.attrs||r.toJSON(s))}if(s.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(s.emulateHTTP&&(n==="PUT"||n==="DELETE"||n==="PATCH")){a.type="POST";if(s.emulateJSON)a.data._method=n;var o=s.beforeSend;s.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",n);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!s.emulateJSON){a.processData=false}if(a.type==="PATCH"&&k){a.xhr=function(){return new ActiveXObject("Microsoft.XMLHTTP")}}var h=s.xhr=e.ajax(i.extend(a,s));r.trigger("request",r,h,s);return h};var k=typeof window!=="undefined"&&!!window.ActiveXObject&&!(window.XMLHttpRequest&&(new XMLHttpRequest).dispatchEvent);var T={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var S=/\((.*?)\)/g;var H=/(\(\?)?:\w+/g;var A=/\*\w+/g;var I=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,u,{initialize:function(){},route:function(t,r,s){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){s=r;r=""}if(!s)s=this[r];var n=this;e.history.route(t,function(i){var a=n._extractParameters(t,i);n.execute(s,a);n.trigger.apply(n,["route:"+r].concat(a));n.trigger("route",r,a);e.history.trigger("route",n,r,a)});return this},execute:function(t,e){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(I,"\\$&").replace(S,"(?:$1)?").replace(H,function(t,e){return e?t:"([^/?]+)"}).replace(A,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var N=e.History=function(){this.handlers=[];i.bindAll(this,"checkUrl");if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var R=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var P=/msie [\w.]+/;var C=/\/$/;var j=/#.*$/;N.started=false;i.extend(N.prototype,u,{interval:50,atRoot:function(){return this.location.pathname.replace(/[^\/]$/,"$&/")===this.root},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getFragment:function(t,e){if(t==null){if(this._hasPushState||!this._wantsHashChange||e){t=decodeURI(this.location.pathname+this.location.search);var i=this.root.replace(C,"");if(!t.indexOf(i))t=t.slice(i.length)}else{t=this.getHash()}}return t.replace(R,"")},start:function(t){if(N.started)throw new Error("Backbone.history has already been started");N.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.options.pushState&&this.history&&this.history.pushState);var r=this.getFragment();var s=document.documentMode;var n=P.exec(navigator.userAgent.toLowerCase())&&(!s||s<=7);this.root=("/"+this.root+"/").replace(O,"/");if(n&&this._wantsHashChange){var a=e.$('<iframe src="javascript:0" tabindex="-1">');this.iframe=a.hide().appendTo("body")[0].contentWindow;this.navigate(r)}if(this._hasPushState){e.$(window).on("popstate",this.checkUrl)}else if(this._wantsHashChange&&"onhashchange"in window&&!n){e.$(window).on("hashchange",this.checkUrl)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}this.fragment=r;var o=this.location;if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){this.fragment=this.getFragment(null,true);this.location.replace(this.root+"#"+this.fragment);return true}else if(this._hasPushState&&this.atRoot()&&o.hash){this.fragment=this.getHash().replace(R,"");this.history.replaceState({},document.title,this.root+this.fragment)}}if(!this.options.silent)return this.loadUrl()},stop:function(){e.$(window).off("popstate",this.checkUrl).off("hashchange",this.checkUrl);if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);N.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getFragment(this.getHash(this.iframe))}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){t=this.fragment=this.getFragment(t);return i.any(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!N.started)return false;if(!e||e===true)e={trigger:!!e};var i=this.root+(t=this.getFragment(t||""));t=t.replace(j,"");if(this.fragment===t)return;this.fragment=t;if(t===""&&i!=="/")i=i.slice(0,-1);if(this._hasPushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,i)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getFragment(this.getHash(this.iframe))){if(!e.replace)this.iframe.document.open().close();this._updateHash(this.iframe.location,t,e.replace)}}else{return this.location.assign(i)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new N;var U=function(t,e){var r=this;var s;if(t&&i.has(t,"constructor")){s=t.constructor}else{s=function(){return r.apply(this,arguments)}}i.extend(s,r,e);var n=function(){this.constructor=s};n.prototype=r.prototype;s.prototype=new n;if(t)i.extend(s.prototype,t);s.__super__=r.prototype;return s};p.extend=g.extend=$.extend=w.extend=N.extend=U;var M=function(){throw new Error('A "url" property or function must be specified')};var q=function(t,e){var i=e.error;e.error=function(r){if(i)i(t,r,e);t.trigger("error",t,r,e)}};return e});
     1(function(t){var e=typeof self=="object"&&self.self==self&&self||typeof global=="object"&&global.global==global&&global;if(typeof define==="function"&&define.amd){define(["underscore","jquery","exports"],function(i,r,n){e.Backbone=t(e,n,i,r)})}else if(typeof exports!=="undefined"){var i=require("underscore"),r;try{r=require("jquery")}catch(n){}t(e,exports,i,r)}else{e.Backbone=t(e,{},e._,e.jQuery||e.Zepto||e.ender||e.$)}})(function(t,e,i,r){var n=t.Backbone;var s=Array.prototype.slice;e.VERSION="1.2.3";e.$=r;e.noConflict=function(){t.Backbone=n;return this};e.emulateHTTP=false;e.emulateJSON=false;var a=function(t,e,r){switch(t){case 1:return function(){return i[e](this[r])};case 2:return function(t){return i[e](this[r],t)};case 3:return function(t,n){return i[e](this[r],h(t,this),n)};case 4:return function(t,n,s){return i[e](this[r],h(t,this),n,s)};default:return function(){var t=s.call(arguments);t.unshift(this[r]);return i[e].apply(i,t)}}};var o=function(t,e,r){i.each(e,function(e,n){if(i[n])t.prototype[n]=a(e,n,r)})};var h=function(t,e){if(i.isFunction(t))return t;if(i.isObject(t)&&!e._isModel(t))return u(t);if(i.isString(t))return function(e){return e.get(t)};return t};var u=function(t){var e=i.matches(t);return function(t){return e(t.attributes)}};var l=e.Events={};var c=/\s+/;var f=function(t,e,r,n,s){var a=0,o;if(r&&typeof r==="object"){if(n!==void 0&&"context"in s&&s.context===void 0)s.context=n;for(o=i.keys(r);a<o.length;a++){e=f(t,e,o[a],r[o[a]],s)}}else if(r&&c.test(r)){for(o=r.split(c);a<o.length;a++){e=t(e,o[a],n,s)}}else{e=t(e,r,n,s)}return e};l.on=function(t,e,i){return d(this,t,e,i)};var d=function(t,e,i,r,n){t._events=f(v,t._events||{},e,i,{context:r,ctx:t,listening:n});if(n){var s=t._listeners||(t._listeners={});s[n.id]=n}return t};l.listenTo=function(t,e,r){if(!t)return this;var n=t._listenId||(t._listenId=i.uniqueId("l"));var s=this._listeningTo||(this._listeningTo={});var a=s[n];if(!a){var o=this._listenId||(this._listenId=i.uniqueId("l"));a=s[n]={obj:t,objId:n,id:o,listeningTo:s,count:0}}d(t,e,r,this,a);return this};var v=function(t,e,i,r){if(i){var n=t[e]||(t[e]=[]);var s=r.context,a=r.ctx,o=r.listening;if(o)o.count++;n.push({callback:i,context:s,ctx:s||a,listening:o})}return t};l.off=function(t,e,i){if(!this._events)return this;this._events=f(g,this._events,t,e,{context:i,listeners:this._listeners});return this};l.stopListening=function(t,e,r){var n=this._listeningTo;if(!n)return this;var s=t?[t._listenId]:i.keys(n);for(var a=0;a<s.length;a++){var o=n[s[a]];if(!o)break;o.obj.off(e,r,this)}if(i.isEmpty(n))this._listeningTo=void 0;return this};var g=function(t,e,r,n){if(!t)return;var s=0,a;var o=n.context,h=n.listeners;if(!e&&!r&&!o){var u=i.keys(h);for(;s<u.length;s++){a=h[u[s]];delete h[a.id];delete a.listeningTo[a.objId]}return}var l=e?[e]:i.keys(t);for(;s<l.length;s++){e=l[s];var c=t[e];if(!c)break;var f=[];for(var d=0;d<c.length;d++){var v=c[d];if(r&&r!==v.callback&&r!==v.callback._callback||o&&o!==v.context){f.push(v)}else{a=v.listening;if(a&&--a.count===0){delete h[a.id];delete a.listeningTo[a.objId]}}}if(f.length){t[e]=f}else{delete t[e]}}if(i.size(t))return t};l.once=function(t,e,r){var n=f(p,{},t,e,i.bind(this.off,this));return this.on(n,void 0,r)};l.listenToOnce=function(t,e,r){var n=f(p,{},e,r,i.bind(this.stopListening,this,t));return this.listenTo(t,n)};var p=function(t,e,r,n){if(r){var s=t[e]=i.once(function(){n(e,s);r.apply(this,arguments)});s._callback=r}return t};l.trigger=function(t){if(!this._events)return this;var e=Math.max(0,arguments.length-1);var i=Array(e);for(var r=0;r<e;r++)i[r]=arguments[r+1];f(m,this._events,t,void 0,i);return this};var m=function(t,e,i,r){if(t){var n=t[e];var s=t.all;if(n&&s)s=s.slice();if(n)_(n,r);if(s)_(s,[e].concat(r))}return t};var _=function(t,e){var i,r=-1,n=t.length,s=e[0],a=e[1],o=e[2];switch(e.length){case 0:while(++r<n)(i=t[r]).callback.call(i.ctx);return;case 1:while(++r<n)(i=t[r]).callback.call(i.ctx,s);return;case 2:while(++r<n)(i=t[r]).callback.call(i.ctx,s,a);return;case 3:while(++r<n)(i=t[r]).callback.call(i.ctx,s,a,o);return;default:while(++r<n)(i=t[r]).callback.apply(i.ctx,e);return}};l.bind=l.on;l.unbind=l.off;i.extend(e,l);var y=e.Model=function(t,e){var r=t||{};e||(e={});this.cid=i.uniqueId(this.cidPrefix);this.attributes={};if(e.collection)this.collection=e.collection;if(e.parse)r=this.parse(r,e)||{};r=i.defaults({},r,i.result(this,"defaults"));this.set(r,e);this.changed={};this.initialize.apply(this,arguments)};i.extend(y.prototype,l,{changed:null,validationError:null,idAttribute:"id",cidPrefix:"c",initialize:function(){},toJSON:function(t){return i.clone(this.attributes)},sync:function(){return e.sync.apply(this,arguments)},get:function(t){return this.attributes[t]},escape:function(t){return i.escape(this.get(t))},has:function(t){return this.get(t)!=null},matches:function(t){return!!i.iteratee(t,this)(this.attributes)},set:function(t,e,r){if(t==null)return this;var n;if(typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r||(r={});if(!this._validate(n,r))return false;var s=r.unset;var a=r.silent;var o=[];var h=this._changing;this._changing=true;if(!h){this._previousAttributes=i.clone(this.attributes);this.changed={}}var u=this.attributes;var l=this.changed;var c=this._previousAttributes;for(var f in n){e=n[f];if(!i.isEqual(u[f],e))o.push(f);if(!i.isEqual(c[f],e)){l[f]=e}else{delete l[f]}s?delete u[f]:u[f]=e}this.id=this.get(this.idAttribute);if(!a){if(o.length)this._pending=r;for(var d=0;d<o.length;d++){this.trigger("change:"+o[d],this,u[o[d]],r)}}if(h)return this;if(!a){while(this._pending){r=this._pending;this._pending=false;this.trigger("change",this,r)}}this._pending=false;this._changing=false;return this},unset:function(t,e){return this.set(t,void 0,i.extend({},e,{unset:true}))},clear:function(t){var e={};for(var r in this.attributes)e[r]=void 0;return this.set(e,i.extend({},t,{unset:true}))},hasChanged:function(t){if(t==null)return!i.isEmpty(this.changed);return i.has(this.changed,t)},changedAttributes:function(t){if(!t)return this.hasChanged()?i.clone(this.changed):false;var e=this._changing?this._previousAttributes:this.attributes;var r={};for(var n in t){var s=t[n];if(i.isEqual(e[n],s))continue;r[n]=s}return i.size(r)?r:false},previous:function(t){if(t==null||!this._previousAttributes)return null;return this._previousAttributes[t]},previousAttributes:function(){return i.clone(this._previousAttributes)},fetch:function(t){t=i.extend({parse:true},t);var e=this;var r=t.success;t.success=function(i){var n=t.parse?e.parse(i,t):i;if(!e.set(n,t))return false;if(r)r.call(t.context,e,i,t);e.trigger("sync",e,i,t)};z(this,t);return this.sync("read",this,t)},save:function(t,e,r){var n;if(t==null||typeof t==="object"){n=t;r=e}else{(n={})[t]=e}r=i.extend({validate:true,parse:true},r);var s=r.wait;if(n&&!s){if(!this.set(n,r))return false}else{if(!this._validate(n,r))return false}var a=this;var o=r.success;var h=this.attributes;r.success=function(t){a.attributes=h;var e=r.parse?a.parse(t,r):t;if(s)e=i.extend({},n,e);if(e&&!a.set(e,r))return false;if(o)o.call(r.context,a,t,r);a.trigger("sync",a,t,r)};z(this,r);if(n&&s)this.attributes=i.extend({},h,n);var u=this.isNew()?"create":r.patch?"patch":"update";if(u==="patch"&&!r.attrs)r.attrs=n;var l=this.sync(u,this,r);this.attributes=h;return l},destroy:function(t){t=t?i.clone(t):{};var e=this;var r=t.success;var n=t.wait;var s=function(){e.stopListening();e.trigger("destroy",e,e.collection,t)};t.success=function(i){if(n)s();if(r)r.call(t.context,e,i,t);if(!e.isNew())e.trigger("sync",e,i,t)};var a=false;if(this.isNew()){i.defer(t.success)}else{z(this,t);a=this.sync("delete",this,t)}if(!n)s();return a},url:function(){var t=i.result(this,"urlRoot")||i.result(this.collection,"url")||F();if(this.isNew())return t;var e=this.get(this.idAttribute);return t.replace(/[^\/]$/,"$&/")+encodeURIComponent(e)},parse:function(t,e){return t},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return!this.has(this.idAttribute)},isValid:function(t){return this._validate({},i.defaults({validate:true},t))},_validate:function(t,e){if(!e.validate||!this.validate)return true;t=i.extend({},this.attributes,t);var r=this.validationError=this.validate(t,e)||null;if(!r)return true;this.trigger("invalid",this,r,i.extend(e,{validationError:r}));return false}});var b={keys:1,values:1,pairs:1,invert:1,pick:0,omit:0,chain:1,isEmpty:1};o(y,b,"attributes");var x=e.Collection=function(t,e){e||(e={});if(e.model)this.model=e.model;if(e.comparator!==void 0)this.comparator=e.comparator;this._reset();this.initialize.apply(this,arguments);if(t)this.reset(t,i.extend({silent:true},e))};var w={add:true,remove:true,merge:true};var E={add:true,remove:false};var k=function(t,e,i){i=Math.min(Math.max(i,0),t.length);var r=Array(t.length-i);var n=e.length;for(var s=0;s<r.length;s++)r[s]=t[s+i];for(s=0;s<n;s++)t[s+i]=e[s];for(s=0;s<r.length;s++)t[s+n+i]=r[s]};i.extend(x.prototype,l,{model:y,initialize:function(){},toJSON:function(t){return this.map(function(e){return e.toJSON(t)})},sync:function(){return e.sync.apply(this,arguments)},add:function(t,e){return this.set(t,i.extend({merge:false},e,E))},remove:function(t,e){e=i.extend({},e);var r=!i.isArray(t);t=r?[t]:i.clone(t);var n=this._removeModels(t,e);if(!e.silent&&n)this.trigger("update",this,e);return r?n[0]:n},set:function(t,e){if(t==null)return;e=i.defaults({},e,w);if(e.parse&&!this._isModel(t))t=this.parse(t,e);var r=!i.isArray(t);t=r?[t]:t.slice();var n=e.at;if(n!=null)n=+n;if(n<0)n+=this.length+1;var s=[];var a=[];var o=[];var h={};var u=e.add;var l=e.merge;var c=e.remove;var f=false;var d=this.comparator&&n==null&&e.sort!==false;var v=i.isString(this.comparator)?this.comparator:null;var g;for(var p=0;p<t.length;p++){g=t[p];var m=this.get(g);if(m){if(l&&g!==m){var _=this._isModel(g)?g.attributes:g;if(e.parse)_=m.parse(_,e);m.set(_,e);if(d&&!f)f=m.hasChanged(v)}if(!h[m.cid]){h[m.cid]=true;s.push(m)}t[p]=m}else if(u){g=t[p]=this._prepareModel(g,e);if(g){a.push(g);this._addReference(g,e);h[g.cid]=true;s.push(g)}}}if(c){for(p=0;p<this.length;p++){g=this.models[p];if(!h[g.cid])o.push(g)}if(o.length)this._removeModels(o,e)}var y=false;var b=!d&&u&&c;if(s.length&&b){y=this.length!=s.length||i.some(this.models,function(t,e){return t!==s[e]});this.models.length=0;k(this.models,s,0);this.length=this.models.length}else if(a.length){if(d)f=true;k(this.models,a,n==null?this.length:n);this.length=this.models.length}if(f)this.sort({silent:true});if(!e.silent){for(p=0;p<a.length;p++){if(n!=null)e.index=n+p;g=a[p];g.trigger("add",g,this,e)}if(f||y)this.trigger("sort",this,e);if(a.length||o.length)this.trigger("update",this,e)}return r?t[0]:t},reset:function(t,e){e=e?i.clone(e):{};for(var r=0;r<this.models.length;r++){this._removeReference(this.models[r],e)}e.previousModels=this.models;this._reset();t=this.add(t,i.extend({silent:true},e));if(!e.silent)this.trigger("reset",this,e);return t},push:function(t,e){return this.add(t,i.extend({at:this.length},e))},pop:function(t){var e=this.at(this.length-1);return this.remove(e,t)},unshift:function(t,e){return this.add(t,i.extend({at:0},e))},shift:function(t){var e=this.at(0);return this.remove(e,t)},slice:function(){return s.apply(this.models,arguments)},get:function(t){if(t==null)return void 0;var e=this.modelId(this._isModel(t)?t.attributes:t);return this._byId[t]||this._byId[e]||this._byId[t.cid]},at:function(t){if(t<0)t+=this.length;return this.models[t]},where:function(t,e){return this[e?"find":"filter"](t)},findWhere:function(t){return this.where(t,true)},sort:function(t){var e=this.comparator;if(!e)throw new Error("Cannot sort a set without a comparator");t||(t={});var r=e.length;if(i.isFunction(e))e=i.bind(e,this);if(r===1||i.isString(e)){this.models=this.sortBy(e)}else{this.models.sort(e)}if(!t.silent)this.trigger("sort",this,t);return this},pluck:function(t){return i.invoke(this.models,"get",t)},fetch:function(t){t=i.extend({parse:true},t);var e=t.success;var r=this;t.success=function(i){var n=t.reset?"reset":"set";r[n](i,t);if(e)e.call(t.context,r,i,t);r.trigger("sync",r,i,t)};z(this,t);return this.sync("read",this,t)},create:function(t,e){e=e?i.clone(e):{};var r=e.wait;t=this._prepareModel(t,e);if(!t)return false;if(!r)this.add(t,e);var n=this;var s=e.success;e.success=function(t,e,i){if(r)n.add(t,i);if(s)s.call(i.context,t,e,i)};t.save(null,e);return t},parse:function(t,e){return t},clone:function(){return new this.constructor(this.models,{model:this.model,comparator:this.comparator})},modelId:function(t){return t[this.model.prototype.idAttribute||"id"]},_reset:function(){this.length=0;this.models=[];this._byId={}},_prepareModel:function(t,e){if(this._isModel(t)){if(!t.collection)t.collection=this;return t}e=e?i.clone(e):{};e.collection=this;var r=new this.model(t,e);if(!r.validationError)return r;this.trigger("invalid",this,r.validationError,e);return false},_removeModels:function(t,e){var i=[];for(var r=0;r<t.length;r++){var n=this.get(t[r]);if(!n)continue;var s=this.indexOf(n);this.models.splice(s,1);this.length--;if(!e.silent){e.index=s;n.trigger("remove",n,this,e)}i.push(n);this._removeReference(n,e)}return i.length?i:false},_isModel:function(t){return t instanceof y},_addReference:function(t,e){this._byId[t.cid]=t;var i=this.modelId(t.attributes);if(i!=null)this._byId[i]=t;t.on("all",this._onModelEvent,this)},_removeReference:function(t,e){delete this._byId[t.cid];var i=this.modelId(t.attributes);if(i!=null)delete this._byId[i];if(this===t.collection)delete t.collection;t.off("all",this._onModelEvent,this)},_onModelEvent:function(t,e,i,r){if((t==="add"||t==="remove")&&i!==this)return;if(t==="destroy")this.remove(e,r);if(t==="change"){var n=this.modelId(e.previousAttributes());var s=this.modelId(e.attributes);if(n!==s){if(n!=null)delete this._byId[n];if(s!=null)this._byId[s]=e}}this.trigger.apply(this,arguments)}});var S={forEach:3,each:3,map:3,collect:3,reduce:4,foldl:4,inject:4,reduceRight:4,foldr:4,find:3,detect:3,filter:3,select:3,reject:3,every:3,all:3,some:3,any:3,include:3,includes:3,contains:3,invoke:0,max:3,min:3,toArray:1,size:1,first:3,head:3,take:3,initial:3,rest:3,tail:3,drop:3,last:3,without:0,difference:0,indexOf:3,shuffle:1,lastIndexOf:3,isEmpty:1,chain:1,sample:3,partition:3,groupBy:3,countBy:3,sortBy:3,indexBy:3};o(x,S,"models");var I=e.View=function(t){this.cid=i.uniqueId("view");i.extend(this,i.pick(t,P));this._ensureElement();this.initialize.apply(this,arguments)};var T=/^(\S+)\s*(.*)$/;var P=["model","collection","el","id","attributes","className","tagName","events"];i.extend(I.prototype,l,{tagName:"div",$:function(t){return this.$el.find(t)},initialize:function(){},render:function(){return this},remove:function(){this._removeElement();this.stopListening();return this},_removeElement:function(){this.$el.remove()},setElement:function(t){this.undelegateEvents();this._setElement(t);this.delegateEvents();return this},_setElement:function(t){this.$el=t instanceof e.$?t:e.$(t);this.el=this.$el[0]},delegateEvents:function(t){t||(t=i.result(this,"events"));if(!t)return this;this.undelegateEvents();for(var e in t){var r=t[e];if(!i.isFunction(r))r=this[r];if(!r)continue;var n=e.match(T);this.delegate(n[1],n[2],i.bind(r,this))}return this},delegate:function(t,e,i){this.$el.on(t+".delegateEvents"+this.cid,e,i);return this},undelegateEvents:function(){if(this.$el)this.$el.off(".delegateEvents"+this.cid);return this},undelegate:function(t,e,i){this.$el.off(t+".delegateEvents"+this.cid,e,i);return this},_createElement:function(t){return document.createElement(t)},_ensureElement:function(){if(!this.el){var t=i.extend({},i.result(this,"attributes"));if(this.id)t.id=i.result(this,"id");if(this.className)t["class"]=i.result(this,"className");this.setElement(this._createElement(i.result(this,"tagName")));this._setAttributes(t)}else{this.setElement(i.result(this,"el"))}},_setAttributes:function(t){this.$el.attr(t)}});e.sync=function(t,r,n){var s=H[t];i.defaults(n||(n={}),{emulateHTTP:e.emulateHTTP,emulateJSON:e.emulateJSON});var a={type:s,dataType:"json"};if(!n.url){a.url=i.result(r,"url")||F()}if(n.data==null&&r&&(t==="create"||t==="update"||t==="patch")){a.contentType="application/json";a.data=JSON.stringify(n.attrs||r.toJSON(n))}if(n.emulateJSON){a.contentType="application/x-www-form-urlencoded";a.data=a.data?{model:a.data}:{}}if(n.emulateHTTP&&(s==="PUT"||s==="DELETE"||s==="PATCH")){a.type="POST";if(n.emulateJSON)a.data._method=s;var o=n.beforeSend;n.beforeSend=function(t){t.setRequestHeader("X-HTTP-Method-Override",s);if(o)return o.apply(this,arguments)}}if(a.type!=="GET"&&!n.emulateJSON){a.processData=false}var h=n.error;n.error=function(t,e,i){n.textStatus=e;n.errorThrown=i;if(h)h.call(n.context,t,e,i)};var u=n.xhr=e.ajax(i.extend(a,n));r.trigger("request",r,u,n);return u};var H={create:"POST",update:"PUT",patch:"PATCH","delete":"DELETE",read:"GET"};e.ajax=function(){return e.$.ajax.apply(e.$,arguments)};var $=e.Router=function(t){t||(t={});if(t.routes)this.routes=t.routes;this._bindRoutes();this.initialize.apply(this,arguments)};var A=/\((.*?)\)/g;var C=/(\(\?)?:\w+/g;var R=/\*\w+/g;var j=/[\-{}\[\]+?.,\\\^$|#\s]/g;i.extend($.prototype,l,{initialize:function(){},route:function(t,r,n){if(!i.isRegExp(t))t=this._routeToRegExp(t);if(i.isFunction(r)){n=r;r=""}if(!n)n=this[r];var s=this;e.history.route(t,function(i){var a=s._extractParameters(t,i);if(s.execute(n,a,r)!==false){s.trigger.apply(s,["route:"+r].concat(a));s.trigger("route",r,a);e.history.trigger("route",s,r,a)}});return this},execute:function(t,e,i){if(t)t.apply(this,e)},navigate:function(t,i){e.history.navigate(t,i);return this},_bindRoutes:function(){if(!this.routes)return;this.routes=i.result(this,"routes");var t,e=i.keys(this.routes);while((t=e.pop())!=null){this.route(t,this.routes[t])}},_routeToRegExp:function(t){t=t.replace(j,"\\$&").replace(A,"(?:$1)?").replace(C,function(t,e){return e?t:"([^/?]+)"}).replace(R,"([^?]*?)");return new RegExp("^"+t+"(?:\\?([\\s\\S]*))?$")},_extractParameters:function(t,e){var r=t.exec(e).slice(1);return i.map(r,function(t,e){if(e===r.length-1)return t||null;return t?decodeURIComponent(t):null})}});var M=e.History=function(){this.handlers=[];this.checkUrl=i.bind(this.checkUrl,this);if(typeof window!=="undefined"){this.location=window.location;this.history=window.history}};var N=/^[#\/]|\s+$/g;var O=/^\/+|\/+$/g;var U=/#.*$/;M.started=false;i.extend(M.prototype,l,{interval:50,atRoot:function(){var t=this.location.pathname.replace(/[^\/]$/,"$&/");return t===this.root&&!this.getSearch()},matchRoot:function(){var t=this.decodeFragment(this.location.pathname);var e=t.slice(0,this.root.length-1)+"/";return e===this.root},decodeFragment:function(t){return decodeURI(t.replace(/%25/g,"%2525"))},getSearch:function(){var t=this.location.href.replace(/#.*/,"").match(/\?.+/);return t?t[0]:""},getHash:function(t){var e=(t||this).location.href.match(/#(.*)$/);return e?e[1]:""},getPath:function(){var t=this.decodeFragment(this.location.pathname+this.getSearch()).slice(this.root.length-1);return t.charAt(0)==="/"?t.slice(1):t},getFragment:function(t){if(t==null){if(this._usePushState||!this._wantsHashChange){t=this.getPath()}else{t=this.getHash()}}return t.replace(N,"")},start:function(t){if(M.started)throw new Error("Backbone.history has already been started");M.started=true;this.options=i.extend({root:"/"},this.options,t);this.root=this.options.root;this._wantsHashChange=this.options.hashChange!==false;this._hasHashChange="onhashchange"in window&&(document.documentMode===void 0||document.documentMode>7);this._useHashChange=this._wantsHashChange&&this._hasHashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=!!(this.history&&this.history.pushState);this._usePushState=this._wantsPushState&&this._hasPushState;this.fragment=this.getFragment();this.root=("/"+this.root+"/").replace(O,"/");if(this._wantsHashChange&&this._wantsPushState){if(!this._hasPushState&&!this.atRoot()){var e=this.root.slice(0,-1)||"/";this.location.replace(e+"#"+this.getPath());return true}else if(this._hasPushState&&this.atRoot()){this.navigate(this.getHash(),{replace:true})}}if(!this._hasHashChange&&this._wantsHashChange&&!this._usePushState){this.iframe=document.createElement("iframe");this.iframe.src="javascript:0";this.iframe.style.display="none";this.iframe.tabIndex=-1;var r=document.body;var n=r.insertBefore(this.iframe,r.firstChild).contentWindow;n.document.open();n.document.close();n.location.hash="#"+this.fragment}var s=window.addEventListener||function(t,e){return attachEvent("on"+t,e)};if(this._usePushState){s("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){s("hashchange",this.checkUrl,false)}else if(this._wantsHashChange){this._checkUrlInterval=setInterval(this.checkUrl,this.interval)}if(!this.options.silent)return this.loadUrl()},stop:function(){var t=window.removeEventListener||function(t,e){return detachEvent("on"+t,e)};if(this._usePushState){t("popstate",this.checkUrl,false)}else if(this._useHashChange&&!this.iframe){t("hashchange",this.checkUrl,false)}if(this.iframe){document.body.removeChild(this.iframe);this.iframe=null}if(this._checkUrlInterval)clearInterval(this._checkUrlInterval);M.started=false},route:function(t,e){this.handlers.unshift({route:t,callback:e})},checkUrl:function(t){var e=this.getFragment();if(e===this.fragment&&this.iframe){e=this.getHash(this.iframe.contentWindow)}if(e===this.fragment)return false;if(this.iframe)this.navigate(e);this.loadUrl()},loadUrl:function(t){if(!this.matchRoot())return false;t=this.fragment=this.getFragment(t);return i.some(this.handlers,function(e){if(e.route.test(t)){e.callback(t);return true}})},navigate:function(t,e){if(!M.started)return false;if(!e||e===true)e={trigger:!!e};t=this.getFragment(t||"");var i=this.root;if(t===""||t.charAt(0)==="?"){i=i.slice(0,-1)||"/"}var r=i+t;t=this.decodeFragment(t.replace(U,""));if(this.fragment===t)return;this.fragment=t;if(this._usePushState){this.history[e.replace?"replaceState":"pushState"]({},document.title,r)}else if(this._wantsHashChange){this._updateHash(this.location,t,e.replace);if(this.iframe&&t!==this.getHash(this.iframe.contentWindow)){var n=this.iframe.contentWindow;if(!e.replace){n.document.open();n.document.close()}this._updateHash(n.location,t,e.replace)}}else{return this.location.assign(r)}if(e.trigger)return this.loadUrl(t)},_updateHash:function(t,e,i){if(i){var r=t.href.replace(/(javascript:|#).*$/,"");t.replace(r+"#"+e)}else{t.hash="#"+e}}});e.history=new M;var q=function(t,e){var r=this;var n;if(t&&i.has(t,"constructor")){n=t.constructor}else{n=function(){return r.apply(this,arguments)}}i.extend(n,r,e);var s=function(){this.constructor=n};s.prototype=r.prototype;n.prototype=new s;if(t)i.extend(n.prototype,t);n.__super__=r.prototype;return n};y.extend=x.extend=$.extend=I.extend=M.extend=q;var F=function(){throw new Error('A "url" property or function must be specified')};var z=function(t,e){var i=e.error;e.error=function(r){if(i)i.call(e.context,t,r,e);t.trigger("error",t,r,e)}};return e});
  • trunk/src/wp-includes/js/media-audiovideo.js

    r36233 r36546  
    729729        this.on( 'media:setting:remove', this.render );
    730730        this.on( 'media:setting:remove', this.setPlayer );
    731         this.events = _.extend( this.events, {
     731
     732        AttachmentDisplay.prototype.initialize.apply( this, arguments );
     733    },
     734
     735    events: function(){
     736        return _.extend( {
    732737            'click .remove-setting' : 'removeSetting',
    733738            'change .content-track' : 'setTracks',
    734739            'click .remove-track' : 'setTracks',
    735740            'click .add-media-source' : 'addSource'
    736         } );
    737 
    738         AttachmentDisplay.prototype.initialize.apply( this, arguments );
     741        }, AttachmentDisplay.prototype.events );
    739742    },
    740743
  • trunk/src/wp-includes/js/media/views/media-details.js

    r36233 r36546  
    2424        this.on( 'media:setting:remove', this.render );
    2525        this.on( 'media:setting:remove', this.setPlayer );
    26         this.events = _.extend( this.events, {
     26
     27        AttachmentDisplay.prototype.initialize.apply( this, arguments );
     28    },
     29
     30    events: function(){
     31        return _.extend( {
    2732            'click .remove-setting' : 'removeSetting',
    2833            'change .content-track' : 'setTracks',
    2934            'click .remove-track' : 'setTracks',
    3035            'click .add-media-source' : 'addSource'
    31         } );
    32 
    33         AttachmentDisplay.prototype.initialize.apply( this, arguments );
     36        }, AttachmentDisplay.prototype.events );
    3437    },
    3538
  • trunk/src/wp-includes/js/underscore.js

    r31471 r36546  
    1 //     Underscore.js 1.6.0
     1//     Underscore.js 1.8.3
    22//     http://underscorejs.org
    3 //     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
     3//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
    44//     Underscore may be freely distributed under the MIT license.
    55
     
    1414  // Save the previous value of the `_` variable.
    1515  var previousUnderscore = root._;
    16 
    17   // Establish the object that gets returned to break out of a loop iteration.
    18   var breaker = {};
    1916
    2017  // Save bytes in the minified (but not gzipped) version:
     
    2522    push             = ArrayProto.push,
    2623    slice            = ArrayProto.slice,
    27     concat           = ArrayProto.concat,
    2824    toString         = ObjProto.toString,
    2925    hasOwnProperty   = ObjProto.hasOwnProperty;
     
    3228  // are declared here.
    3329  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,
    4330    nativeIsArray      = Array.isArray,
    4431    nativeKeys         = Object.keys,
    45     nativeBind         = FuncProto.bind;
     32    nativeBind         = FuncProto.bind,
     33    nativeCreate       = Object.create;
     34
     35  // Naked function reference for surrogate-prototype-swapping.
     36  var Ctor = function(){};
    4637
    4738  // Create a safe reference to the Underscore object for use below.
     
    5445  // Export the Underscore object for **Node.js**, with
    5546  // 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.
     47  // the browser, add `_` as a global object.
    5848  if (typeof exports !== 'undefined') {
    5949    if (typeof module !== 'undefined' && module.exports) {
     
    6656
    6757  // Current version.
    68   _.VERSION = '1.6.0';
     58  _.VERSION = '1.8.3';
     59
     60  // Internal function that returns an efficient (for current engines) version
     61  // of the passed-in callback, to be repeatedly applied in other Underscore
     62  // functions.
     63  var optimizeCb = function(func, context, argCount) {
     64    if (context === void 0) return func;
     65    switch (argCount == null ? 3 : argCount) {
     66      case 1: return function(value) {
     67        return func.call(context, value);
     68      };
     69      case 2: return function(value, other) {
     70        return func.call(context, value, other);
     71      };
     72      case 3: return function(value, index, collection) {
     73        return func.call(context, value, index, collection);
     74      };
     75      case 4: return function(accumulator, value, index, collection) {
     76        return func.call(context, accumulator, value, index, collection);
     77      };
     78    }
     79    return function() {
     80      return func.apply(context, arguments);
     81    };
     82  };
     83
     84  // A mostly-internal function to generate callbacks that can be applied
     85  // to each element in a collection, returning the desired result — either
     86  // identity, an arbitrary callback, a property matcher, or a property accessor.
     87  var cb = function(value, context, argCount) {
     88    if (value == null) return _.identity;
     89    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
     90    if (_.isObject(value)) return _.matcher(value);
     91    return _.property(value);
     92  };
     93  _.iteratee = function(value, context) {
     94    return cb(value, context, Infinity);
     95  };
     96
     97  // An internal function for creating assigner functions.
     98  var createAssigner = function(keysFunc, undefinedOnly) {
     99    return function(obj) {
     100      var length = arguments.length;
     101      if (length < 2 || obj == null) return obj;
     102      for (var index = 1; index < length; index++) {
     103        var source = arguments[index],
     104            keys = keysFunc(source),
     105            l = keys.length;
     106        for (var i = 0; i < l; i++) {
     107          var key = keys[i];
     108          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
     109        }
     110      }
     111      return obj;
     112    };
     113  };
     114
     115  // An internal function for creating a new object that inherits from another.
     116  var baseCreate = function(prototype) {
     117    if (!_.isObject(prototype)) return {};
     118    if (nativeCreate) return nativeCreate(prototype);
     119    Ctor.prototype = prototype;
     120    var result = new Ctor;
     121    Ctor.prototype = null;
     122    return result;
     123  };
     124
     125  var property = function(key) {
     126    return function(obj) {
     127      return obj == null ? void 0 : obj[key];
     128    };
     129  };
     130
     131  // Helper for collection methods to determine whether a collection
     132  // should be iterated as an array or as an object
     133  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
     134  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
     135  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
     136  var getLength = property('length');
     137  var isArrayLike = function(collection) {
     138    var length = getLength(collection);
     139    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
     140  };
    69141
    70142  // Collection Functions
     
    72144
    73145  // 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 (obj == null) return obj;
    78     if (nativeForEach && obj.forEach === nativeForEach) {
    79       obj.forEach(iterator, context);
    80     } else if (obj.length === +obj.length) {
    81       for (var i = 0, length = obj.length; i < length; i++) {
    82         if (iterator.call(context, obj[i], i, obj) === breaker) return;
     146  // Handles raw objects in addition to array-likes. Treats all
     147  // sparse array-likes as if they were dense.
     148  _.each = _.forEach = function(obj, iteratee, context) {
     149    iteratee = optimizeCb(iteratee, context);
     150    var i, length;
     151    if (isArrayLike(obj)) {
     152      for (i = 0, length = obj.length; i < length; i++) {
     153        iteratee(obj[i], i, obj);
    83154      }
    84155    } else {
    85156      var keys = _.keys(obj);
    86       for (var i = 0, length = keys.length; i < length; i++) {
    87         if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
     157      for (i = 0, length = keys.length; i < length; i++) {
     158        iteratee(obj[keys[i]], keys[i], obj);
    88159      }
    89160    }
     
    91162  };
    92163
    93   // Return the results of applying the iterator to each element.
    94   // Delegates to **ECMAScript 5**'s native `map` if available.
    95   _.map = _.collect = function(obj, iterator, context) {
    96     var results = [];
    97     if (obj == null) return results;
    98     if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
    99     each(obj, function(value, index, list) {
    100       results.push(iterator.call(context, value, index, list));
    101     });
     164  // Return the results of applying the iteratee to each element.
     165  _.map = _.collect = function(obj, iteratee, context) {
     166    iteratee = cb(iteratee, context);
     167    var keys = !isArrayLike(obj) && _.keys(obj),
     168        length = (keys || obj).length,
     169        results = Array(length);
     170    for (var index = 0; index < length; index++) {
     171      var currentKey = keys ? keys[index] : index;
     172      results[index] = iteratee(obj[currentKey], currentKey, obj);
     173    }
    102174    return results;
    103175  };
    104176
    105   var reduceError = 'Reduce of empty array with no initial value';
     177  // Create a reducing function iterating left or right.
     178  function createReduce(dir) {
     179    // Optimized iterator function as using arguments.length
     180    // in the main function will deoptimize the, see #1991.
     181    function iterator(obj, iteratee, memo, keys, index, length) {
     182      for (; index >= 0 && index < length; index += dir) {
     183        var currentKey = keys ? keys[index] : index;
     184        memo = iteratee(memo, obj[currentKey], currentKey, obj);
     185      }
     186      return memo;
     187    }
     188
     189    return function(obj, iteratee, memo, context) {
     190      iteratee = optimizeCb(iteratee, context, 4);
     191      var keys = !isArrayLike(obj) && _.keys(obj),
     192          length = (keys || obj).length,
     193          index = dir > 0 ? 0 : length - 1;
     194      // Determine the initial value if none is provided.
     195      if (arguments.length < 3) {
     196        memo = obj[keys ? keys[index] : index];
     197        index += dir;
     198      }
     199      return iterator(obj, iteratee, memo, keys, index, length);
     200    };
     201  }
    106202
    107203  // **Reduce** builds up a single result from a list of values, aka `inject`,
    108   // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
    109   _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
    110     var initial = arguments.length > 2;
    111     if (obj == null) obj = [];
    112     if (nativeReduce && obj.reduce === nativeReduce) {
    113       if (context) iterator = _.bind(iterator, context);
    114       return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
    115     }
    116     each(obj, function(value, index, list) {
    117       if (!initial) {
    118         memo = value;
    119         initial = true;
    120       } else {
    121         memo = iterator.call(context, memo, value, index, list);
    122       }
    123     });
    124     if (!initial) throw new TypeError(reduceError);
    125     return memo;
    126   };
     204  // or `foldl`.
     205  _.reduce = _.foldl = _.inject = createReduce(1);
    127206
    128207  // The right-associative version of reduce, also known as `foldr`.
    129   // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
    130   _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
    131     var initial = arguments.length > 2;
    132     if (obj == null) obj = [];
    133     if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
    134       if (context) iterator = _.bind(iterator, context);
    135       return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
    136     }
    137     var length = obj.length;
    138     if (length !== +length) {
    139       var keys = _.keys(obj);
    140       length = keys.length;
    141     }
    142     each(obj, function(value, index, list) {
    143       index = keys ? keys[--length] : --length;
    144       if (!initial) {
    145         memo = obj[index];
    146         initial = true;
    147       } else {
    148         memo = iterator.call(context, memo, obj[index], index, list);
    149       }
    150     });
    151     if (!initial) throw new TypeError(reduceError);
    152     return memo;
    153   };
     208  _.reduceRight = _.foldr = createReduce(-1);
    154209
    155210  // Return the first value which passes a truth test. Aliased as `detect`.
    156211  _.find = _.detect = function(obj, predicate, context) {
    157     var result;
    158     any(obj, function(value, index, list) {
    159       if (predicate.call(context, value, index, list)) {
    160         result = value;
    161         return true;
    162       }
    163     });
    164     return result;
     212    var key;
     213    if (isArrayLike(obj)) {
     214      key = _.findIndex(obj, predicate, context);
     215    } else {
     216      key = _.findKey(obj, predicate, context);
     217    }
     218    if (key !== void 0 && key !== -1) return obj[key];
    165219  };
    166220
    167221  // Return all the elements that pass a truth test.
    168   // Delegates to **ECMAScript 5**'s native `filter` if available.
    169222  // Aliased as `select`.
    170223  _.filter = _.select = function(obj, predicate, context) {
    171224    var results = [];
    172     if (obj == null) return results;
    173     if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
    174     each(obj, function(value, index, list) {
    175       if (predicate.call(context, value, index, list)) results.push(value);
     225    predicate = cb(predicate, context);
     226    _.each(obj, function(value, index, list) {
     227      if (predicate(value, index, list)) results.push(value);
    176228    });
    177229    return results;
     
    180232  // Return all the elements for which a truth test fails.
    181233  _.reject = function(obj, predicate, context) {
    182     return _.filter(obj, function(value, index, list) {
    183       return !predicate.call(context, value, index, list);
    184     }, context);
     234    return _.filter(obj, _.negate(cb(predicate)), context);
    185235  };
    186236
    187237  // Determine whether all of the elements match a truth test.
    188   // Delegates to **ECMAScript 5**'s native `every` if available.
    189238  // Aliased as `all`.
    190239  _.every = _.all = function(obj, predicate, context) {
    191     predicate || (predicate = _.identity);
    192     var result = true;
    193     if (obj == null) return result;
    194     if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
    195     each(obj, function(value, index, list) {
    196       if (!(result = result && predicate.call(context, value, index, list))) return breaker;
    197     });
    198     return !!result;
     240    predicate = cb(predicate, context);
     241    var keys = !isArrayLike(obj) && _.keys(obj),
     242        length = (keys || obj).length;
     243    for (var index = 0; index < length; index++) {
     244      var currentKey = keys ? keys[index] : index;
     245      if (!predicate(obj[currentKey], currentKey, obj)) return false;
     246    }
     247    return true;
    199248  };
    200249
    201250  // Determine if at least one element in the object matches a truth test.
    202   // Delegates to **ECMAScript 5**'s native `some` if available.
    203251  // Aliased as `any`.
    204   var any = _.some = _.any = function(obj, predicate, context) {
    205     predicate || (predicate = _.identity);
    206     var result = false;
    207     if (obj == null) return result;
    208     if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
    209     each(obj, function(value, index, list) {
    210       if (result || (result = predicate.call(context, value, index, list))) return breaker;
    211     });
    212     return !!result;
    213   };
    214 
    215   // Determine if the array or object contains a given value (using `===`).
    216   // Aliased as `include`.
    217   _.contains = _.include = function(obj, target) {
    218     if (obj == null) return false;
    219     if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
    220     return any(obj, function(value) {
    221       return value === target;
    222     });
     252  _.some = _.any = function(obj, predicate, context) {
     253    predicate = cb(predicate, context);
     254    var keys = !isArrayLike(obj) && _.keys(obj),
     255        length = (keys || obj).length;
     256    for (var index = 0; index < length; index++) {
     257      var currentKey = keys ? keys[index] : index;
     258      if (predicate(obj[currentKey], currentKey, obj)) return true;
     259    }
     260    return false;
     261  };
     262
     263  // Determine if the array or object contains a given item (using `===`).
     264  // Aliased as `includes` and `include`.
     265  _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
     266    if (!isArrayLike(obj)) obj = _.values(obj);
     267    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
     268    return _.indexOf(obj, item, fromIndex) >= 0;
    223269  };
    224270
     
    228274    var isFunc = _.isFunction(method);
    229275    return _.map(obj, function(value) {
    230       return (isFunc ? method : value[method]).apply(value, args);
     276      var func = isFunc ? method : value[method];
     277      return func == null ? func : func.apply(value, args);
    231278    });
    232279  };
     
    240287  // containing specific `key:value` pairs.
    241288  _.where = function(obj, attrs) {
    242     return _.filter(obj, _.matches(attrs));
     289    return _.filter(obj, _.matcher(attrs));
    243290  };
    244291
     
    246293  // containing specific `key:value` pairs.
    247294  _.findWhere = function(obj, attrs) {
    248     return _.find(obj, _.matches(attrs));
    249   };
    250 
    251   // Return the maximum element or (element-based computation).
    252   // Can't optimize arrays of integers longer than 65,535 elements.
    253   // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
    254   _.max = function(obj, iterator, context) {
    255     if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    256       return Math.max.apply(Math, obj);
    257     }
    258     var result = -Infinity, lastComputed = -Infinity;
    259     each(obj, function(value, index, list) {
    260       var computed = iterator ? iterator.call(context, value, index, list) : value;
    261       if (computed > lastComputed) {
    262         result = value;
    263         lastComputed = computed;
    264       }
    265     });
     295    return _.find(obj, _.matcher(attrs));
     296  };
     297
     298  // Return the maximum element (or element-based computation).
     299  _.max = function(obj, iteratee, context) {
     300    var result = -Infinity, lastComputed = -Infinity,
     301        value, computed;
     302    if (iteratee == null && obj != null) {
     303      obj = isArrayLike(obj) ? obj : _.values(obj);
     304      for (var i = 0, length = obj.length; i < length; i++) {
     305        value = obj[i];
     306        if (value > result) {
     307          result = value;
     308        }
     309      }
     310    } else {
     311      iteratee = cb(iteratee, context);
     312      _.each(obj, function(value, index, list) {
     313        computed = iteratee(value, index, list);
     314        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
     315          result = value;
     316          lastComputed = computed;
     317        }
     318      });
     319    }
    266320    return result;
    267321  };
    268322
    269323  // Return the minimum element (or element-based computation).
    270   _.min = function(obj, iterator, context) {
    271     if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
    272       return Math.min.apply(Math, obj);
    273     }
    274     var result = Infinity, lastComputed = Infinity;
    275     each(obj, function(value, index, list) {
    276       var computed = iterator ? iterator.call(context, value, index, list) : value;
    277       if (computed < lastComputed) {
    278         result = value;
    279         lastComputed = computed;
    280       }
    281     });
     324  _.min = function(obj, iteratee, context) {
     325    var result = Infinity, lastComputed = Infinity,
     326        value, computed;
     327    if (iteratee == null && obj != null) {
     328      obj = isArrayLike(obj) ? obj : _.values(obj);
     329      for (var i = 0, length = obj.length; i < length; i++) {
     330        value = obj[i];
     331        if (value < result) {
     332          result = value;
     333        }
     334      }
     335    } else {
     336      iteratee = cb(iteratee, context);
     337      _.each(obj, function(value, index, list) {
     338        computed = iteratee(value, index, list);
     339        if (computed < lastComputed || computed === Infinity && result === Infinity) {
     340          result = value;
     341          lastComputed = computed;
     342        }
     343      });
     344    }
    282345    return result;
    283346  };
    284347
    285   // Shuffle an array, using the modern version of the
     348  // Shuffle a collection, using the modern version of the
    286349  // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
    287350  _.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     });
     351    var set = isArrayLike(obj) ? obj : _.values(obj);
     352    var length = set.length;
     353    var shuffled = Array(length);
     354    for (var index = 0, rand; index < length; index++) {
     355      rand = _.random(0, index);
     356      if (rand !== index) shuffled[index] = shuffled[rand];
     357      shuffled[rand] = set[index];
     358    }
    296359    return shuffled;
    297360  };
     
    302365  _.sample = function(obj, n, guard) {
    303366    if (n == null || guard) {
    304       if (obj.length !== +obj.length) obj = _.values(obj);
     367      if (!isArrayLike(obj)) obj = _.values(obj);
    305368      return obj[_.random(obj.length - 1)];
    306369    }
     
    308371  };
    309372
    310   // An internal function to generate lookup iterators.
    311   var lookupIterator = function(value) {
    312     if (value == null) return _.identity;
    313     if (_.isFunction(value)) return value;
    314     return _.property(value);
    315   };
    316 
    317   // Sort the object's values by a criterion produced by an iterator.
    318   _.sortBy = function(obj, iterator, context) {
    319     iterator = lookupIterator(iterator);
     373  // Sort the object's values by a criterion produced by an iteratee.
     374  _.sortBy = function(obj, iteratee, context) {
     375    iteratee = cb(iteratee, context);
    320376    return _.pluck(_.map(obj, function(value, index, list) {
    321377      return {
    322378        value: value,
    323379        index: index,
    324         criteria: iterator.call(context, value, index, list)
     380        criteria: iteratee(value, index, list)
    325381      };
    326382    }).sort(function(left, right) {
     
    337393  // An internal function used for aggregate "group by" operations.
    338394  var group = function(behavior) {
    339     return function(obj, iterator, context) {
     395    return function(obj, iteratee, context) {
    340396      var result = {};
    341       iterator = lookupIterator(iterator);
    342       each(obj, function(value, index) {
    343         var key = iterator.call(context, value, index, obj);
    344         behavior(result, key, value);
     397      iteratee = cb(iteratee, context);
     398      _.each(obj, function(value, index) {
     399        var key = iteratee(value, index, obj);
     400        behavior(result, value, key);
    345401      });
    346402      return result;
     
    350406  // Groups the object's values by a criterion. Pass either a string attribute
    351407  // to group by, or a function that returns the criterion.
    352   _.groupBy = group(function(result, key, value) {
    353     _.has(result, key) ? result[key].push(value) : result[key] = [value];
     408  _.groupBy = group(function(result, value, key) {
     409    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
    354410  });
    355411
    356412  // Indexes the object's values by a criterion, similar to `groupBy`, but for
    357413  // when you know that your index values will be unique.
    358   _.indexBy = group(function(result, key, value) {
     414  _.indexBy = group(function(result, value, key) {
    359415    result[key] = value;
    360416  });
     
    363419  // either a string attribute to count by, or a function that returns the
    364420  // criterion.
    365   _.countBy = group(function(result, key) {
    366     _.has(result, key) ? result[key]++ : result[key] = 1;
     421  _.countBy = group(function(result, value, key) {
     422    if (_.has(result, key)) result[key]++; else result[key] = 1;
    367423  });
    368 
    369   // Use a comparator function to figure out the smallest index at which
    370   // an object should be inserted so as to maintain order. Uses binary search.
    371   _.sortedIndex = function(array, obj, iterator, context) {
    372     iterator = lookupIterator(iterator);
    373     var value = iterator.call(context, obj);
    374     var low = 0, high = array.length;
    375     while (low < high) {
    376       var mid = (low + high) >>> 1;
    377       iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
    378     }
    379     return low;
    380   };
    381424
    382425  // Safely create a real, live array from anything iterable.
     
    384427    if (!obj) return [];
    385428    if (_.isArray(obj)) return slice.call(obj);
    386     if (obj.length === +obj.length) return _.map(obj, _.identity);
     429    if (isArrayLike(obj)) return _.map(obj, _.identity);
    387430    return _.values(obj);
    388431  };
     
    391434  _.size = function(obj) {
    392435    if (obj == null) return 0;
    393     return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
     436    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
     437  };
     438
     439  // Split a collection into two arrays: one whose elements all satisfy the given
     440  // predicate, and one whose elements all do not satisfy the predicate.
     441  _.partition = function(obj, predicate, context) {
     442    predicate = cb(predicate, context);
     443    var pass = [], fail = [];
     444    _.each(obj, function(value, key, obj) {
     445      (predicate(value, key, obj) ? pass : fail).push(value);
     446    });
     447    return [pass, fail];
    394448  };
    395449
     
    402456  _.first = _.head = _.take = function(array, n, guard) {
    403457    if (array == null) return void 0;
    404     if ((n == null) || guard) return array[0];
    405     if (n < 0) return [];
    406     return slice.call(array, 0, n);
     458    if (n == null || guard) return array[0];
     459    return _.initial(array, array.length - n);
    407460  };
    408461
    409462  // Returns everything but the last entry of the array. Especially useful on
    410463  // the arguments object. Passing **n** will return all the values in
    411   // the array, excluding the last N. The **guard** check allows it to work with
    412   // `_.map`.
     464  // the array, excluding the last N.
    413465  _.initial = function(array, n, guard) {
    414     return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
     466    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
    415467  };
    416468
    417469  // Get the last element of an array. Passing **n** will return the last N
    418   // values in the array. The **guard** check allows it to work with `_.map`.
     470  // values in the array.
    419471  _.last = function(array, n, guard) {
    420472    if (array == null) return void 0;
    421     if ((n == null) || guard) return array[array.length - 1];
    422     return slice.call(array, Math.max(array.length - n, 0));
     473    if (n == null || guard) return array[array.length - 1];
     474    return _.rest(array, Math.max(0, array.length - n));
    423475  };
    424476
    425477  // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
    426478  // Especially useful on the arguments object. Passing an **n** will return
    427   // the rest N values in the array. The **guard**
    428   // check allows it to work with `_.map`.
     479  // the rest N values in the array.
    429480  _.rest = _.tail = _.drop = function(array, n, guard) {
    430     return slice.call(array, (n == null) || guard ? 1 : n);
     481    return slice.call(array, n == null || guard ? 1 : n);
    431482  };
    432483
     
    437488
    438489  // Internal implementation of a recursive `flatten` function.
    439   var flatten = function(input, shallow, output) {
    440     if (shallow && _.every(input, _.isArray)) {
    441       return concat.apply(output, input);
    442     }
    443     each(input, function(value) {
    444       if (_.isArray(value) || _.isArguments(value)) {
    445         shallow ? push.apply(output, value) : flatten(value, shallow, output);
    446       } else {
    447         output.push(value);
    448       }
    449     });
     490  var flatten = function(input, shallow, strict, startIndex) {
     491    var output = [], idx = 0;
     492    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
     493      var value = input[i];
     494      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
     495        //flatten current level of array or arguments object
     496        if (!shallow) value = flatten(value, shallow, strict);
     497        var j = 0, len = value.length;
     498        output.length += len;
     499        while (j < len) {
     500          output[idx++] = value[j++];
     501        }
     502      } else if (!strict) {
     503        output[idx++] = value;
     504      }
     505    }
    450506    return output;
    451507  };
     
    453509  // Flatten out an array, either recursively (by default), or just one level.
    454510  _.flatten = function(array, shallow) {
    455     return flatten(array, shallow, []);
     511    return flatten(array, shallow, false);
    456512  };
    457513
     
    461517  };
    462518
    463   // Split an array into two arrays: one whose elements all satisfy the given
    464   // predicate, and one whose elements all do not satisfy the predicate.
    465   _.partition = function(array, predicate) {
    466     var pass = [], fail = [];
    467     each(array, function(elem) {
    468       (predicate(elem) ? pass : fail).push(elem);
    469     });
    470     return [pass, fail];
    471   };
    472 
    473519  // Produce a duplicate-free version of the array. If the array has already
    474520  // been sorted, you have the option of using a faster algorithm.
    475521  // Aliased as `unique`.
    476   _.uniq = _.unique = function(array, isSorted, iterator, context) {
    477     if (_.isFunction(isSorted)) {
    478       context = iterator;
    479       iterator = isSorted;
     522  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
     523    if (!_.isBoolean(isSorted)) {
     524      context = iteratee;
     525      iteratee = isSorted;
    480526      isSorted = false;
    481527    }
    482     var initial = iterator ? _.map(array, iterator, context) : array;
    483     var results = [];
     528    if (iteratee != null) iteratee = cb(iteratee, context);
     529    var result = [];
    484530    var seen = [];
    485     each(initial, function(value, index) {
    486       if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
    487         seen.push(value);
    488         results.push(array[index]);
    489       }
    490     });
    491     return results;
     531    for (var i = 0, length = getLength(array); i < length; i++) {
     532      var value = array[i],
     533          computed = iteratee ? iteratee(value, i, array) : value;
     534      if (isSorted) {
     535        if (!i || seen !== computed) result.push(value);
     536        seen = computed;
     537      } else if (iteratee) {
     538        if (!_.contains(seen, computed)) {
     539          seen.push(computed);
     540          result.push(value);
     541        }
     542      } else if (!_.contains(result, value)) {
     543        result.push(value);
     544      }
     545    }
     546    return result;
    492547  };
    493548
     
    495550  // the passed-in arrays.
    496551  _.union = function() {
    497     return _.uniq(_.flatten(arguments, true));
     552    return _.uniq(flatten(arguments, true, true));
    498553  };
    499554
     
    501556  // passed-in arrays.
    502557  _.intersection = function(array) {
    503     var rest = slice.call(arguments, 1);
    504     return _.filter(_.uniq(array), function(item) {
    505       return _.every(rest, function(other) {
    506         return _.contains(other, item);
    507       });
    508     });
     558    var result = [];
     559    var argsLength = arguments.length;
     560    for (var i = 0, length = getLength(array); i < length; i++) {
     561      var item = array[i];
     562      if (_.contains(result, item)) continue;
     563      for (var j = 1; j < argsLength; j++) {
     564        if (!_.contains(arguments[j], item)) break;
     565      }
     566      if (j === argsLength) result.push(item);
     567    }
     568    return result;
    509569  };
    510570
     
    512572  // Only the elements present in just the first array will remain.
    513573  _.difference = function(array) {
    514     var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
    515     return _.filter(array, function(value){ return !_.contains(rest, value); });
     574    var rest = flatten(arguments, true, true, 1);
     575    return _.filter(array, function(value){
     576      return !_.contains(rest, value);
     577    });
    516578  };
    517579
     
    519581  // an index go together.
    520582  _.zip = function() {
    521     var length = _.max(_.pluck(arguments, 'length').concat(0));
    522     var results = new Array(length);
    523     for (var i = 0; i < length; i++) {
    524       results[i] = _.pluck(arguments, '' + i);
    525     }
    526     return results;
     583    return _.unzip(arguments);
     584  };
     585
     586  // Complement of _.zip. Unzip accepts an array of arrays and groups
     587  // each array's elements on shared indices
     588  _.unzip = function(array) {
     589    var length = array && _.max(array, getLength).length || 0;
     590    var result = Array(length);
     591
     592    for (var index = 0; index < length; index++) {
     593      result[index] = _.pluck(array, index);
     594    }
     595    return result;
    527596  };
    528597
     
    531600  // the corresponding values.
    532601  _.object = function(list, values) {
    533     if (list == null) return {};
    534602    var result = {};
    535     for (var i = 0, length = list.length; i < length; i++) {
     603    for (var i = 0, length = getLength(list); i < length; i++) {
    536604      if (values) {
    537605        result[list[i]] = values[i];
     
    543611  };
    544612
    545   // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
    546   // we need this function. Return the position of the first occurrence of an
    547   // item in an array, or -1 if the item is not included in the array.
    548   // Delegates to **ECMAScript 5**'s native `indexOf` if available.
     613  // Generator function to create the findIndex and findLastIndex functions
     614  function createPredicateIndexFinder(dir) {
     615    return function(array, predicate, context) {
     616      predicate = cb(predicate, context);
     617      var length = getLength(array);
     618      var index = dir > 0 ? 0 : length - 1;
     619      for (; index >= 0 && index < length; index += dir) {
     620        if (predicate(array[index], index, array)) return index;
     621      }
     622      return -1;
     623    };
     624  }
     625
     626  // Returns the first index on an array-like that passes a predicate test
     627  _.findIndex = createPredicateIndexFinder(1);
     628  _.findLastIndex = createPredicateIndexFinder(-1);
     629
     630  // Use a comparator function to figure out the smallest index at which
     631  // an object should be inserted so as to maintain order. Uses binary search.
     632  _.sortedIndex = function(array, obj, iteratee, context) {
     633    iteratee = cb(iteratee, context, 1);
     634    var value = iteratee(obj);
     635    var low = 0, high = getLength(array);
     636    while (low < high) {
     637      var mid = Math.floor((low + high) / 2);
     638      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
     639    }
     640    return low;
     641  };
     642
     643  // Generator function to create the indexOf and lastIndexOf functions
     644  function createIndexFinder(dir, predicateFind, sortedIndex) {
     645    return function(array, item, idx) {
     646      var i = 0, length = getLength(array);
     647      if (typeof idx == 'number') {
     648        if (dir > 0) {
     649            i = idx >= 0 ? idx : Math.max(idx + length, i);
     650        } else {
     651            length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
     652        }
     653      } else if (sortedIndex && idx && length) {
     654        idx = sortedIndex(array, item);
     655        return array[idx] === item ? idx : -1;
     656      }
     657      if (item !== item) {
     658        idx = predicateFind(slice.call(array, i, length), _.isNaN);
     659        return idx >= 0 ? idx + i : -1;
     660      }
     661      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
     662        if (array[idx] === item) return idx;
     663      }
     664      return -1;
     665    };
     666  }
     667
     668  // Return the position of the first occurrence of an item in an array,
     669  // or -1 if the item is not included in the array.
    549670  // If the array is large and already in sort order, pass `true`
    550671  // for **isSorted** to use binary search.
    551   _.indexOf = function(array, item, isSorted) {
    552     if (array == null) return -1;
    553     var i = 0, length = array.length;
    554     if (isSorted) {
    555       if (typeof isSorted == 'number') {
    556         i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
    557       } else {
    558         i = _.sortedIndex(array, item);
    559         return array[i] === item ? i : -1;
    560       }
    561     }
    562     if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
    563     for (; i < length; i++) if (array[i] === item) return i;
    564     return -1;
    565   };
    566 
    567   // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
    568   _.lastIndexOf = function(array, item, from) {
    569     if (array == null) return -1;
    570     var hasIndex = from != null;
    571     if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
    572       return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
    573     }
    574     var i = (hasIndex ? from : array.length);
    575     while (i--) if (array[i] === item) return i;
    576     return -1;
    577   };
     672  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
     673  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
    578674
    579675  // Generate an integer Array containing an arithmetic progression. A port of
     
    581677  // [the Python documentation](http://docs.python.org/library/functions.html#range).
    582678  _.range = function(start, stop, step) {
    583     if (arguments.length <= 1) {
     679    if (stop == null) {
    584680      stop = start || 0;
    585681      start = 0;
    586682    }
    587     step = arguments[2] || 1;
     683    step = step || 1;
    588684
    589685    var length = Math.max(Math.ceil((stop - start) / step), 0);
    590     var idx = 0;
    591     var range = new Array(length);
    592 
    593     while(idx < length) {
    594       range[idx++] = start;
    595       start += step;
     686    var range = Array(length);
     687
     688    for (var idx = 0; idx < length; idx++, start += step) {
     689      range[idx] = start;
    596690    }
    597691
     
    602696  // ------------------
    603697
    604   // Reusable constructor function for prototype setting.
    605   var ctor = function(){};
     698  // Determines whether to execute a function as a constructor
     699  // or a normal function with the provided arguments
     700  var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
     701    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
     702    var self = baseCreate(sourceFunc.prototype);
     703    var result = sourceFunc.apply(self, args);
     704    if (_.isObject(result)) return result;
     705    return self;
     706  };
    606707
    607708  // Create a function bound to a given object (assigning `this`, and arguments,
     
    609710  // available.
    610711  _.bind = function(func, context) {
    611     var args, bound;
    612712    if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
    613     if (!_.isFunction(func)) throw new TypeError;
    614     args = slice.call(arguments, 2);
    615     return bound = function() {
    616       if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
    617       ctor.prototype = func.prototype;
    618       var self = new ctor;
    619       ctor.prototype = null;
    620       var result = func.apply(self, args.concat(slice.call(arguments)));
    621       if (Object(result) === result) return result;
    622       return self;
    623     };
     713    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
     714    var args = slice.call(arguments, 2);
     715    var bound = function() {
     716      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
     717    };
     718    return bound;
    624719  };
    625720
     
    629724  _.partial = function(func) {
    630725    var boundArgs = slice.call(arguments, 1);
    631     return function() {
    632       var position = 0;
    633       var args = boundArgs.slice();
    634       for (var i = 0, length = args.length; i < length; i++) {
    635         if (args[i] === _) args[i] = arguments[position++];
     726    var bound = function() {
     727      var position = 0, length = boundArgs.length;
     728      var args = Array(length);
     729      for (var i = 0; i < length; i++) {
     730        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
    636731      }
    637732      while (position < arguments.length) args.push(arguments[position++]);
    638       return func.apply(this, args);
    639     };
     733      return executeBound(func, bound, this, this, args);
     734    };
     735    return bound;
    640736  };
    641737
     
    644740  // defined on an object belong to it.
    645741  _.bindAll = function(obj) {
    646     var funcs = slice.call(arguments, 1);
    647     if (funcs.length === 0) throw new Error('bindAll must be passed function names');
    648     each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
     742    var i, length = arguments.length, key;
     743    if (length <= 1) throw new Error('bindAll must be passed function names');
     744    for (i = 1; i < length; i++) {
     745      key = arguments[i];
     746      obj[key] = _.bind(obj[key], obj);
     747    }
    649748    return obj;
    650749  };
     
    652751  // Memoize an expensive function by storing its results.
    653752  _.memoize = function(func, hasher) {
    654     var memo = {};
    655     hasher || (hasher = _.identity);
    656     return function() {
    657       var key = hasher.apply(this, arguments);
    658       return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
    659     };
     753    var memoize = function(key) {
     754      var cache = memoize.cache;
     755      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
     756      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
     757      return cache[address];
     758    };
     759    memoize.cache = {};
     760    return memoize;
    660761  };
    661762
     
    664765  _.delay = function(func, wait) {
    665766    var args = slice.call(arguments, 2);
    666     return setTimeout(function(){ return func.apply(null, args); }, wait);
     767    return setTimeout(function(){
     768      return func.apply(null, args);
     769    }, wait);
    667770  };
    668771
    669772  // Defers a function, scheduling it to run after the current call stack has
    670773  // cleared.
    671   _.defer = function(func) {
    672     return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
    673   };
     774  _.defer = _.partial(_.delay, _, 1);
    674775
    675776  // Returns a function, that, when invoked, will only be triggered at most once
     
    682783    var timeout = null;
    683784    var previous = 0;
    684     options || (options = {});
     785    if (!options) options = {};
    685786    var later = function() {
    686787      previous = options.leading === false ? 0 : _.now();
    687788      timeout = null;
    688789      result = func.apply(context, args);
    689       context = args = null;
     790      if (!timeout) context = args = null;
    690791    };
    691792    return function() {
     
    695796      context = this;
    696797      args = arguments;
    697       if (remaining <= 0) {
    698         clearTimeout(timeout);
    699         timeout = null;
     798      if (remaining <= 0 || remaining > wait) {
     799        if (timeout) {
     800          clearTimeout(timeout);
     801          timeout = null;
     802        }
    700803        previous = now;
    701804        result = func.apply(context, args);
    702         context = args = null;
     805        if (!timeout) context = args = null;
    703806      } else if (!timeout && options.trailing !== false) {
    704807        timeout = setTimeout(later, remaining);
     
    717820    var later = function() {
    718821      var last = _.now() - timestamp;
    719       if (last < wait) {
     822
     823      if (last < wait && last >= 0) {
    720824        timeout = setTimeout(later, wait - last);
    721825      } else {
     
    723827        if (!immediate) {
    724828          result = func.apply(context, args);
    725           context = args = null;
     829          if (!timeout) context = args = null;
    726830        }
    727831      }
     
    733837      timestamp = _.now();
    734838      var callNow = immediate && !timeout;
    735       if (!timeout) {
    736         timeout = setTimeout(later, wait);
    737       }
     839      if (!timeout) timeout = setTimeout(later, wait);
    738840      if (callNow) {
    739841        result = func.apply(context, args);
     
    742844
    743845      return result;
    744     };
    745   };
    746 
    747   // Returns a function that will be executed at most one time, no matter how
    748   // often you call it. Useful for lazy initialization.
    749   _.once = function(func) {
    750     var ran = false, memo;
    751     return function() {
    752       if (ran) return memo;
    753       ran = true;
    754       memo = func.apply(this, arguments);
    755       func = null;
    756       return memo;
    757846    };
    758847  };
     
    765854  };
    766855
     856  // Returns a negated version of the passed-in predicate.
     857  _.negate = function(predicate) {
     858    return function() {
     859      return !predicate.apply(this, arguments);
     860    };
     861  };
     862
    767863  // Returns a function that is the composition of a list of functions, each
    768864  // consuming the return value of the function that follows.
    769865  _.compose = function() {
    770     var funcs = arguments;
     866    var args = arguments;
     867    var start = args.length - 1;
    771868    return function() {
    772       var args = arguments;
    773       for (var i = funcs.length - 1; i >= 0; i--) {
    774         args = [funcs[i].apply(this, args)];
    775       }
    776       return args[0];
    777     };
    778   };
    779 
    780   // Returns a function that will only be executed after being called N times.
     869      var i = start;
     870      var result = args[start].apply(this, arguments);
     871      while (i--) result = args[i].call(this, result);
     872      return result;
     873    };
     874  };
     875
     876  // Returns a function that will only be executed on and after the Nth call.
    781877  _.after = function(times, func) {
    782878    return function() {
     
    787883  };
    788884
     885  // Returns a function that will only be executed up to (but not including) the Nth call.
     886  _.before = function(times, func) {
     887    var memo;
     888    return function() {
     889      if (--times > 0) {
     890        memo = func.apply(this, arguments);
     891      }
     892      if (times <= 1) func = null;
     893      return memo;
     894    };
     895  };
     896
     897  // Returns a function that will be executed at most one time, no matter how
     898  // often you call it. Useful for lazy initialization.
     899  _.once = _.partial(_.before, 2);
     900
    789901  // Object Functions
    790902  // ----------------
    791903
    792   // Retrieve the names of an object's properties.
     904  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
     905  var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
     906  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
     907                      'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
     908
     909  function collectNonEnumProps(obj, keys) {
     910    var nonEnumIdx = nonEnumerableProps.length;
     911    var constructor = obj.constructor;
     912    var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
     913
     914    // Constructor is a special case.
     915    var prop = 'constructor';
     916    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
     917
     918    while (nonEnumIdx--) {
     919      prop = nonEnumerableProps[nonEnumIdx];
     920      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
     921        keys.push(prop);
     922      }
     923    }
     924  }
     925
     926  // Retrieve the names of an object's own properties.
    793927  // Delegates to **ECMAScript 5**'s native `Object.keys`
    794928  _.keys = function(obj) {
     
    797931    var keys = [];
    798932    for (var key in obj) if (_.has(obj, key)) keys.push(key);
     933    // Ahem, IE < 9.
     934    if (hasEnumBug) collectNonEnumProps(obj, keys);
     935    return keys;
     936  };
     937
     938  // Retrieve all the property names of an object.
     939  _.allKeys = function(obj) {
     940    if (!_.isObject(obj)) return [];
     941    var keys = [];
     942    for (var key in obj) keys.push(key);
     943    // Ahem, IE < 9.
     944    if (hasEnumBug) collectNonEnumProps(obj, keys);
    799945    return keys;
    800946  };
     
    804950    var keys = _.keys(obj);
    805951    var length = keys.length;
    806     var values = new Array(length);
     952    var values = Array(length);
    807953    for (var i = 0; i < length; i++) {
    808954      values[i] = obj[keys[i]];
    809955    }
    810956    return values;
     957  };
     958
     959  // Returns the results of applying the iteratee to each element of the object
     960  // In contrast to _.map it returns an object
     961  _.mapObject = function(obj, iteratee, context) {
     962    iteratee = cb(iteratee, context);
     963    var keys =  _.keys(obj),
     964          length = keys.length,
     965          results = {},
     966          currentKey;
     967      for (var index = 0; index < length; index++) {
     968        currentKey = keys[index];
     969        results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
     970      }
     971      return results;
    811972  };
    812973
     
    815976    var keys = _.keys(obj);
    816977    var length = keys.length;
    817     var pairs = new Array(length);
     978    var pairs = Array(length);
    818979    for (var i = 0; i < length; i++) {
    819980      pairs[i] = [keys[i], obj[keys[i]]];
     
    8431004
    8441005  // Extend a given object with all the properties in passed-in object(s).
    845   _.extend = function(obj) {
    846     each(slice.call(arguments, 1), function(source) {
    847       if (source) {
    848         for (var prop in source) {
    849           obj[prop] = source[prop];
    850         }
    851       }
    852     });
    853     return obj;
     1006  _.extend = createAssigner(_.allKeys);
     1007
     1008  // Assigns a given object with all the own properties in the passed-in object(s)
     1009  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
     1010  _.extendOwn = _.assign = createAssigner(_.keys);
     1011
     1012  // Returns the first key on an object that passes a predicate test
     1013  _.findKey = function(obj, predicate, context) {
     1014    predicate = cb(predicate, context);
     1015    var keys = _.keys(obj), key;
     1016    for (var i = 0, length = keys.length; i < length; i++) {
     1017      key = keys[i];
     1018      if (predicate(obj[key], key, obj)) return key;
     1019    }
    8541020  };
    8551021
    8561022  // Return a copy of the object only containing the whitelisted properties.
    857   _.pick = function(obj) {
    858     var copy = {};
    859     var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    860     each(keys, function(key) {
    861       if (key in obj) copy[key] = obj[key];
    862     });
    863     return copy;
     1023  _.pick = function(object, oiteratee, context) {
     1024    var result = {}, obj = object, iteratee, keys;
     1025    if (obj == null) return result;
     1026    if (_.isFunction(oiteratee)) {
     1027      keys = _.allKeys(obj);
     1028      iteratee = optimizeCb(oiteratee, context);
     1029    } else {
     1030      keys = flatten(arguments, false, false, 1);
     1031      iteratee = function(value, key, obj) { return key in obj; };
     1032      obj = Object(obj);
     1033    }
     1034    for (var i = 0, length = keys.length; i < length; i++) {
     1035      var key = keys[i];
     1036      var value = obj[key];
     1037      if (iteratee(value, key, obj)) result[key] = value;
     1038    }
     1039    return result;
    8641040  };
    8651041
    8661042   // Return a copy of the object without the blacklisted properties.
    867   _.omit = function(obj) {
    868     var copy = {};
    869     var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
    870     for (var key in obj) {
    871       if (!_.contains(keys, key)) copy[key] = obj[key];
    872     }
    873     return copy;
     1043  _.omit = function(obj, iteratee, context) {
     1044    if (_.isFunction(iteratee)) {
     1045      iteratee = _.negate(iteratee);
     1046    } else {
     1047      var keys = _.map(flatten(arguments, false, false, 1), String);
     1048      iteratee = function(value, key) {
     1049        return !_.contains(keys, key);
     1050      };
     1051    }
     1052    return _.pick(obj, iteratee, context);
    8741053  };
    8751054
    8761055  // Fill in a given object with default properties.
    877   _.defaults = function(obj) {
    878     each(slice.call(arguments, 1), function(source) {
    879       if (source) {
    880         for (var prop in source) {
    881           if (obj[prop] === void 0) obj[prop] = source[prop];
    882         }
    883       }
    884     });
    885     return obj;
     1056  _.defaults = createAssigner(_.allKeys, true);
     1057
     1058  // Creates an object that inherits from the given prototype object.
     1059  // If additional properties are provided then they will be added to the
     1060  // created object.
     1061  _.create = function(prototype, props) {
     1062    var result = baseCreate(prototype);
     1063    if (props) _.extendOwn(result, props);
     1064    return result;
    8861065  };
    8871066
     
    9001079  };
    9011080
     1081  // Returns whether an object has a given set of `key:value` pairs.
     1082  _.isMatch = function(object, attrs) {
     1083    var keys = _.keys(attrs), length = keys.length;
     1084    if (object == null) return !length;
     1085    var obj = Object(object);
     1086    for (var i = 0; i < length; i++) {
     1087      var key = keys[i];
     1088      if (attrs[key] !== obj[key] || !(key in obj)) return false;
     1089    }
     1090    return true;
     1091  };
     1092
     1093
    9021094  // Internal recursive comparison function for `isEqual`.
    9031095  var eq = function(a, b, aStack, bStack) {
    9041096    // Identical objects are equal. `0 === -0`, but they aren't identical.
    9051097    // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
    906     if (a === b) return a !== 0 || 1 / a == 1 / b;
     1098    if (a === b) return a !== 0 || 1 / a === 1 / b;
    9071099    // A strict comparison is necessary because `null == undefined`.
    9081100    if (a == null || b == null) return a === b;
     
    9121104    // Compare `[[Class]]` names.
    9131105    var className = toString.call(a);
    914     if (className != toString.call(b)) return false;
     1106    if (className !== toString.call(b)) return false;
    9151107    switch (className) {
    916       // Strings, numbers, dates, and booleans are compared by value.
     1108      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
     1109      case '[object RegExp]':
     1110      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
    9171111      case '[object String]':
    9181112        // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
    9191113        // equivalent to `new String("5")`.
    920         return a == String(b);
     1114        return '' + a === '' + b;
    9211115      case '[object Number]':
    922         // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
    923         // other numeric values.
    924         return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
     1116        // `NaN`s are equivalent, but non-reflexive.
     1117        // Object(NaN) is equivalent to NaN
     1118        if (+a !== +a) return +b !== +b;
     1119        // An `egal` comparison is performed for other numeric values.
     1120        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
    9251121      case '[object Date]':
    9261122      case '[object Boolean]':
     
    9281124        // millisecond representations. Note that invalid dates with millisecond representations
    9291125        // of `NaN` are not equivalent.
    930         return +a == +b;
    931       // RegExps are compared by their source patterns and flags.
    932       case '[object RegExp]':
    933         return a.source == b.source &&
    934                a.global == b.global &&
    935                a.multiline == b.multiline &&
    936                a.ignoreCase == b.ignoreCase;
    937     }
    938     if (typeof a != 'object' || typeof b != 'object') return false;
     1126        return +a === +b;
     1127    }
     1128
     1129    var areArrays = className === '[object Array]';
     1130    if (!areArrays) {
     1131      if (typeof a != 'object' || typeof b != 'object') return false;
     1132
     1133      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
     1134      // from different frames are.
     1135      var aCtor = a.constructor, bCtor = b.constructor;
     1136      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
     1137                               _.isFunction(bCtor) && bCtor instanceof bCtor)
     1138                          && ('constructor' in a && 'constructor' in b)) {
     1139        return false;
     1140      }
     1141    }
    9391142    // Assume equality for cyclic structures. The algorithm for detecting cyclic
    9401143    // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
     1144
     1145    // Initializing stack of traversed objects.
     1146    // It's done here since we only need them for objects and arrays comparison.
     1147    aStack = aStack || [];
     1148    bStack = bStack || [];
    9411149    var length = aStack.length;
    9421150    while (length--) {
    9431151      // Linear search. Performance is inversely proportional to the number of
    9441152      // unique nested structures.
    945       if (aStack[length] == a) return bStack[length] == b;
    946     }
    947     // Objects with different constructors are not equivalent, but `Object`s
    948     // from different frames are.
    949     var aCtor = a.constructor, bCtor = b.constructor;
    950     if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
    951                              _.isFunction(bCtor) && (bCtor instanceof bCtor))
    952                         && ('constructor' in a && 'constructor' in b)) {
    953       return false;
    954     }
     1153      if (aStack[length] === a) return bStack[length] === b;
     1154    }
     1155
    9551156    // Add the first object to the stack of traversed objects.
    9561157    aStack.push(a);
    9571158    bStack.push(b);
    958     var size = 0, result = true;
     1159
    9591160    // Recursively compare objects and arrays.
    960     if (className == '[object Array]') {
     1161    if (areArrays) {
    9611162      // Compare array lengths to determine if a deep comparison is necessary.
    962       size = a.length;
    963       result = size == b.length;
    964       if (result) {
    965         // Deep compare the contents, ignoring non-numeric properties.
    966         while (size--) {
    967           if (!(result = eq(a[size], b[size], aStack, bStack))) break;
    968         }
     1163      length = a.length;
     1164      if (length !== b.length) return false;
     1165      // Deep compare the contents, ignoring non-numeric properties.
     1166      while (length--) {
     1167        if (!eq(a[length], b[length], aStack, bStack)) return false;
    9691168      }
    9701169    } else {
    9711170      // Deep compare objects.
    972       for (var key in a) {
    973         if (_.has(a, key)) {
    974           // Count the expected number of properties.
    975           size++;
    976           // Deep compare each member.
    977           if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
    978         }
    979       }
    980       // Ensure that both objects contain the same number of properties.
    981       if (result) {
    982         for (key in b) {
    983           if (_.has(b, key) && !(size--)) break;
    984         }
    985         result = !size;
     1171      var keys = _.keys(a), key;
     1172      length = keys.length;
     1173      // Ensure that both objects contain the same number of properties before comparing deep equality.
     1174      if (_.keys(b).length !== length) return false;
     1175      while (length--) {
     1176        // Deep compare each member
     1177        key = keys[length];
     1178        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
    9861179      }
    9871180    }
     
    9891182    aStack.pop();
    9901183    bStack.pop();
    991     return result;
     1184    return true;
    9921185  };
    9931186
    9941187  // Perform a deep comparison to check if two objects are equal.
    9951188  _.isEqual = function(a, b) {
    996     return eq(a, b, [], []);
     1189    return eq(a, b);
    9971190  };
    9981191
     
    10011194  _.isEmpty = function(obj) {
    10021195    if (obj == null) return true;
    1003     if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
    1004     for (var key in obj) if (_.has(obj, key)) return false;
    1005     return true;
     1196    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
     1197    return _.keys(obj).length === 0;
    10061198  };
    10071199
     
    10141206  // Delegates to ECMA5's native Array.isArray
    10151207  _.isArray = nativeIsArray || function(obj) {
    1016     return toString.call(obj) == '[object Array]';
     1208    return toString.call(obj) === '[object Array]';
    10171209  };
    10181210
    10191211  // Is a given variable an object?
    10201212  _.isObject = function(obj) {
    1021     return obj === Object(obj);
    1022   };
    1023 
    1024   // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
    1025   each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
     1213    var type = typeof obj;
     1214    return type === 'function' || type === 'object' && !!obj;
     1215  };
     1216
     1217  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
     1218  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
    10261219    _['is' + name] = function(obj) {
    1027       return toString.call(obj) == '[object ' + name + ']';
     1220      return toString.call(obj) === '[object ' + name + ']';
    10281221    };
    10291222  });
    10301223
    1031   // Define a fallback version of the method in browsers (ahem, IE), where
     1224  // Define a fallback version of the method in browsers (ahem, IE < 9), where
    10321225  // there isn't any inspectable "Arguments" type.
    10331226  if (!_.isArguments(arguments)) {
    10341227    _.isArguments = function(obj) {
    1035       return !!(obj && _.has(obj, 'callee'));
     1228      return _.has(obj, 'callee');
    10361229    };
    10371230  }
    10381231
    1039   // Optimize `isFunction` if appropriate.
    1040   if (typeof (/./) !== 'function') {
     1232  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
     1233  // IE 11 (#1621), and in Safari 8 (#1929).
     1234  if (typeof /./ != 'function' && typeof Int8Array != 'object') {
    10411235    _.isFunction = function(obj) {
    1042       return typeof obj === 'function';
     1236      return typeof obj == 'function' || false;
    10431237    };
    10441238  }
     
    10511245  // Is the given value `NaN`? (NaN is the only number which does not equal itself).
    10521246  _.isNaN = function(obj) {
    1053     return _.isNumber(obj) && obj != +obj;
     1247    return _.isNumber(obj) && obj !== +obj;
    10541248  };
    10551249
    10561250  // Is a given value a boolean?
    10571251  _.isBoolean = function(obj) {
    1058     return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
     1252    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
    10591253  };
    10601254
     
    10721266  // on itself (in other words, not on a prototype).
    10731267  _.has = function(obj, key) {
    1074     return hasOwnProperty.call(obj, key);
     1268    return obj != null && hasOwnProperty.call(obj, key);
    10751269  };
    10761270
     
    10851279  };
    10861280
    1087   // Keep the identity function around for default iterators.
     1281  // Keep the identity function around for default iteratees.
    10881282  _.identity = function(value) {
    10891283    return value;
    10901284  };
    10911285
     1286  // Predicate-generating functions. Often useful outside of Underscore.
    10921287  _.constant = function(value) {
    1093     return function () {
     1288    return function() {
    10941289      return value;
    10951290    };
    10961291  };
    10971292
    1098   _.property = function(key) {
     1293  _.noop = function(){};
     1294
     1295  _.property = property;
     1296
     1297  // Generates a function for a given object that returns a given property.
     1298  _.propertyOf = function(obj) {
     1299    return obj == null ? function(){} : function(key) {
     1300      return obj[key];
     1301    };
     1302  };
     1303
     1304  // Returns a predicate for checking whether an object has a given set of
     1305  // `key:value` pairs.
     1306  _.matcher = _.matches = function(attrs) {
     1307    attrs = _.extendOwn({}, attrs);
    10991308    return function(obj) {
    1100       return obj[key];
    1101     };
    1102   };
    1103 
    1104   // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
    1105   _.matches = function(attrs) {
    1106     return function(obj) {
    1107       if (obj === attrs) return true; //avoid comparing an object to itself.
    1108       for (var key in attrs) {
    1109         if (attrs[key] !== obj[key])
    1110           return false;
    1111       }
    1112       return true;
    1113     }
     1309      return _.isMatch(obj, attrs);
     1310    };
    11141311  };
    11151312
    11161313  // Run a function **n** times.
    1117   _.times = function(n, iterator, context) {
     1314  _.times = function(n, iteratee, context) {
    11181315    var accum = Array(Math.max(0, n));
    1119     for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
     1316    iteratee = optimizeCb(iteratee, context, 1);
     1317    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
    11201318    return accum;
    11211319  };
     
    11311329
    11321330  // A (possibly faster) way to get the current timestamp as an integer.
    1133   _.now = Date.now || function() { return new Date().getTime(); };
    1134 
    1135   // List of HTML entities for escaping.
    1136   var entityMap = {
    1137     escape: {
    1138       '&': '&amp;',
    1139       '<': '&lt;',
    1140       '>': '&gt;',
    1141       '"': '&quot;',
    1142       "'": '&#x27;'
    1143     }
    1144   };
    1145   entityMap.unescape = _.invert(entityMap.escape);
    1146 
    1147   // Regexes containing the keys and values listed immediately above.
    1148   var entityRegexes = {
    1149     escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
    1150     unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
    1151   };
     1331  _.now = Date.now || function() {
     1332    return new Date().getTime();
     1333  };
     1334
     1335   // List of HTML entities for escaping.
     1336  var escapeMap = {
     1337    '&': '&amp;',
     1338    '<': '&lt;',
     1339    '>': '&gt;',
     1340    '"': '&quot;',
     1341    "'": '&#x27;',
     1342    '`': '&#x60;'
     1343  };
     1344  var unescapeMap = _.invert(escapeMap);
    11521345
    11531346  // Functions for escaping and unescaping strings to/from HTML interpolation.
    1154   _.each(['escape', 'unescape'], function(method) {
    1155     _[method] = function(string) {
    1156       if (string == null) return '';
    1157       return ('' + string).replace(entityRegexes[method], function(match) {
    1158         return entityMap[method][match];
    1159       });
    1160     };
    1161   });
     1347  var createEscaper = function(map) {
     1348    var escaper = function(match) {
     1349      return map[match];
     1350    };
     1351    // Regexes for identifying a key that needs to be escaped
     1352    var source = '(?:' + _.keys(map).join('|') + ')';
     1353    var testRegexp = RegExp(source);
     1354    var replaceRegexp = RegExp(source, 'g');
     1355    return function(string) {
     1356      string = string == null ? '' : '' + string;
     1357      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
     1358    };
     1359  };
     1360  _.escape = createEscaper(escapeMap);
     1361  _.unescape = createEscaper(unescapeMap);
    11621362
    11631363  // If the value of the named `property` is a function then invoke it with the
    11641364  // `object` as context; otherwise, return it.
    1165   _.result = function(object, property) {
    1166     if (object == null) return void 0;
    1167     var value = object[property];
     1365  _.result = function(object, property, fallback) {
     1366    var value = object == null ? void 0 : object[property];
     1367    if (value === void 0) {
     1368      value = fallback;
     1369    }
    11681370    return _.isFunction(value) ? value.call(object) : value;
    1169   };
    1170 
    1171   // Add your own custom functions to the Underscore object.
    1172   _.mixin = function(obj) {
    1173     each(_.functions(obj), function(name) {
    1174       var func = _[name] = obj[name];
    1175       _.prototype[name] = function() {
    1176         var args = [this._wrapped];
    1177         push.apply(args, arguments);
    1178         return result.call(this, func.apply(_, args));
    1179       };
    1180     });
    11811371  };
    11821372
     
    12091399    '\r':     'r',
    12101400    '\n':     'n',
    1211     '\t':     't',
    12121401    '\u2028': 'u2028',
    12131402    '\u2029': 'u2029'
    12141403  };
    12151404
    1216   var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
     1405  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
     1406
     1407  var escapeChar = function(match) {
     1408    return '\\' + escapes[match];
     1409  };
    12171410
    12181411  // JavaScript micro-templating, similar to John Resig's implementation.
    12191412  // Underscore templating handles arbitrary delimiters, preserves whitespace,
    12201413  // and correctly escapes quotes within interpolated code.
    1221   _.template = function(text, data, settings) {
    1222     var render;
     1414  // NB: `oldSettings` only exists for backwards compatibility.
     1415  _.template = function(text, settings, oldSettings) {
     1416    if (!settings && oldSettings) settings = oldSettings;
    12231417    settings = _.defaults({}, settings, _.templateSettings);
    12241418
    12251419    // Combine delimiters into one regular expression via alternation.
    1226     var matcher = new RegExp([
     1420    var matcher = RegExp([
    12271421      (settings.escape || noMatch).source,
    12281422      (settings.interpolate || noMatch).source,
     
    12341428    var source = "__p+='";
    12351429    text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
    1236       source += text.slice(index, offset)
    1237         .replace(escaper, function(match) { return '\\' + escapes[match]; });
     1430      source += text.slice(index, offset).replace(escaper, escapeChar);
     1431      index = offset + match.length;
    12381432
    12391433      if (escape) {
    12401434        source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
    1241       }
    1242       if (interpolate) {
     1435      } else if (interpolate) {
    12431436        source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
    1244       }
    1245       if (evaluate) {
     1437      } else if (evaluate) {
    12461438        source += "';\n" + evaluate + "\n__p+='";
    12471439      }
    1248       index = offset + match.length;
     1440
     1441      // Adobe VMs need the match returned to produce the correct offest.
    12491442      return match;
    12501443    });
     
    12561449    source = "var __t,__p='',__j=Array.prototype.join," +
    12571450      "print=function(){__p+=__j.call(arguments,'');};\n" +
    1258       source + "return __p;\n";
     1451      source + 'return __p;\n';
    12591452
    12601453    try {
    1261       render = new Function(settings.variable || 'obj', '_', source);
     1454      var render = new Function(settings.variable || 'obj', '_', source);
    12621455    } catch (e) {
    12631456      e.source = source;
     
    12651458    }
    12661459
    1267     if (data) return render(data, _);
    12681460    var template = function(data) {
    12691461      return render.call(this, data, _);
    12701462    };
    12711463
    1272     // Provide the compiled function source as a convenience for precompilation.
    1273     template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
     1464    // Provide the compiled source as a convenience for precompilation.
     1465    var argument = settings.variable || 'obj';
     1466    template.source = 'function(' + argument + '){\n' + source + '}';
    12741467
    12751468    return template;
    12761469  };
    12771470
    1278   // Add a "chain" function, which will delegate to the wrapper.
     1471  // Add a "chain" function. Start chaining a wrapped Underscore object.
    12791472  _.chain = function(obj) {
    1280     return _(obj).chain();
     1473    var instance = _(obj);
     1474    instance._chain = true;
     1475    return instance;
    12811476  };
    12821477
     
    12881483
    12891484  // Helper function to continue chaining intermediate results.
    1290   var result = function(obj) {
    1291     return this._chain ? _(obj).chain() : obj;
     1485  var result = function(instance, obj) {
     1486    return instance._chain ? _(obj).chain() : obj;
     1487  };
     1488
     1489  // Add your own custom functions to the Underscore object.
     1490  _.mixin = function(obj) {
     1491    _.each(_.functions(obj), function(name) {
     1492      var func = _[name] = obj[name];
     1493      _.prototype[name] = function() {
     1494        var args = [this._wrapped];
     1495        push.apply(args, arguments);
     1496        return result(this, func.apply(_, args));
     1497      };
     1498    });
    12921499  };
    12931500
     
    12961503
    12971504  // Add all mutator Array functions to the wrapper.
    1298   each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
     1505  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
    12991506    var method = ArrayProto[name];
    13001507    _.prototype[name] = function() {
    13011508      var obj = this._wrapped;
    13021509      method.apply(obj, arguments);
    1303       if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
    1304       return result.call(this, obj);
     1510      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
     1511      return result(this, obj);
    13051512    };
    13061513  });
    13071514
    13081515  // Add all accessor Array functions to the wrapper.
    1309   each(['concat', 'join', 'slice'], function(name) {
     1516  _.each(['concat', 'join', 'slice'], function(name) {
    13101517    var method = ArrayProto[name];
    13111518    _.prototype[name] = function() {
    1312       return result.call(this, method.apply(this._wrapped, arguments));
     1519      return result(this, method.apply(this._wrapped, arguments));
    13131520    };
    13141521  });
    13151522
    1316   _.extend(_.prototype, {
    1317 
    1318     // Start chaining a wrapped Underscore object.
    1319     chain: function() {
    1320       this._chain = true;
    1321       return this;
    1322     },
    1323 
    1324     // Extracts the result from a wrapped and chained object.
    1325     value: function() {
    1326       return this._wrapped;
    1327     }
    1328 
    1329   });
     1523  // Extracts the result from a wrapped and chained object.
     1524  _.prototype.value = function() {
     1525    return this._wrapped;
     1526  };
     1527
     1528  // Provide unwrapping proxy for some methods used in engine operations
     1529  // such as arithmetic and JSON stringification.
     1530  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
     1531
     1532  _.prototype.toString = function() {
     1533    return '' + this._wrapped;
     1534  };
    13301535
    13311536  // AMD registration happens at the end for compatibility with AMD loaders
     
    13411546    });
    13421547  }
    1343 }).call(this);
     1548}.call(this));
  • trunk/src/wp-includes/js/underscore.min.js

    r32065 r36546  
    1 //     Underscore.js 1.6.0
     1//     Underscore.js 1.8.3
    22//     http://underscorejs.org
    3 //     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
     3//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
    44//     Underscore may be freely distributed under the MIT license.
    5 (function(){var n=this,t=n._,r={},e=Array.prototype,u=Object.prototype,i=Function.prototype,a=e.push,o=e.slice,c=e.concat,l=u.toString,f=u.hasOwnProperty,s=e.forEach,p=e.map,h=e.reduce,v=e.reduceRight,g=e.filter,d=e.every,m=e.some,y=e.indexOf,b=e.lastIndexOf,x=Array.isArray,w=Object.keys,_=i.bind,j=function(n){return n instanceof j?n:this instanceof j?void(this._wrapped=n):new j(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=j),exports._=j):n._=j,j.VERSION="1.6.0";var A=j.each=j.forEach=function(n,t,e){if(null==n)return n;if(s&&n.forEach===s)n.forEach(t,e);else if(n.length===+n.length){for(var u=0,i=n.length;i>u;u++)if(t.call(e,n[u],u,n)===r)return}else for(var a=j.keys(n),u=0,i=a.length;i>u;u++)if(t.call(e,n[a[u]],a[u],n)===r)return;return n};j.map=j.collect=function(n,t,r){var e=[];return null==n?e:p&&n.map===p?n.map(t,r):(A(n,function(n,u,i){e.push(t.call(r,n,u,i))}),e)};var O="Reduce of empty array with no initial value";j.reduce=j.foldl=j.inject=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),h&&n.reduce===h)return e&&(t=j.bind(t,e)),u?n.reduce(t,r):n.reduce(t);if(A(n,function(n,i,a){u?r=t.call(e,r,n,i,a):(r=n,u=!0)}),!u)throw new TypeError(O);return r},j.reduceRight=j.foldr=function(n,t,r,e){var u=arguments.length>2;if(null==n&&(n=[]),v&&n.reduceRight===v)return e&&(t=j.bind(t,e)),u?n.reduceRight(t,r):n.reduceRight(t);var i=n.length;if(i!==+i){var a=j.keys(n);i=a.length}if(A(n,function(o,c,l){c=a?a[--i]:--i,u?r=t.call(e,r,n[c],c,l):(r=n[c],u=!0)}),!u)throw new TypeError(O);return r},j.find=j.detect=function(n,t,r){var e;return k(n,function(n,u,i){return t.call(r,n,u,i)?(e=n,!0):void 0}),e},j.filter=j.select=function(n,t,r){var e=[];return null==n?e:g&&n.filter===g?n.filter(t,r):(A(n,function(n,u,i){t.call(r,n,u,i)&&e.push(n)}),e)},j.reject=function(n,t,r){return j.filter(n,function(n,e,u){return!t.call(r,n,e,u)},r)},j.every=j.all=function(n,t,e){t||(t=j.identity);var u=!0;return null==n?u:d&&n.every===d?n.every(t,e):(A(n,function(n,i,a){return(u=u&&t.call(e,n,i,a))?void 0:r}),!!u)};var k=j.some=j.any=function(n,t,e){t||(t=j.identity);var u=!1;return null==n?u:m&&n.some===m?n.some(t,e):(A(n,function(n,i,a){return u||(u=t.call(e,n,i,a))?r:void 0}),!!u)};j.contains=j.include=function(n,t){return null==n?!1:y&&n.indexOf===y?n.indexOf(t)!=-1:k(n,function(n){return n===t})},j.invoke=function(n,t){var r=o.call(arguments,2),e=j.isFunction(t);return j.map(n,function(n){return(e?t:n[t]).apply(n,r)})},j.pluck=function(n,t){return j.map(n,j.property(t))},j.where=function(n,t){return j.filter(n,j.matches(t))},j.findWhere=function(n,t){return j.find(n,j.matches(t))},j.max=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.max.apply(Math,n);var e=-1/0,u=-1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;o>u&&(e=n,u=o)}),e},j.min=function(n,t,r){if(!t&&j.isArray(n)&&n[0]===+n[0]&&n.length<65535)return Math.min.apply(Math,n);var e=1/0,u=1/0;return A(n,function(n,i,a){var o=t?t.call(r,n,i,a):n;u>o&&(e=n,u=o)}),e},j.shuffle=function(n){var t,r=0,e=[];return A(n,function(n){t=j.random(r++),e[r-1]=e[t],e[t]=n}),e},j.sample=function(n,t,r){return null==t||r?(n.length!==+n.length&&(n=j.values(n)),n[j.random(n.length-1)]):j.shuffle(n).slice(0,Math.max(0,t))};var E=function(n){return null==n?j.identity:j.isFunction(n)?n:j.property(n)};j.sortBy=function(n,t,r){return t=E(t),j.pluck(j.map(n,function(n,e,u){return{value:n,index:e,criteria:t.call(r,n,e,u)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=E(r),A(t,function(i,a){var o=r.call(e,i,a,t);n(u,o,i)}),u}};j.groupBy=F(function(n,t,r){j.has(n,t)?n[t].push(r):n[t]=[r]}),j.indexBy=F(function(n,t,r){n[t]=r}),j.countBy=F(function(n,t){j.has(n,t)?n[t]++:n[t]=1}),j.sortedIndex=function(n,t,r,e){r=E(r);for(var u=r.call(e,t),i=0,a=n.length;a>i;){var o=i+a>>>1;r.call(e,n[o])<u?i=o+1:a=o}return i},j.toArray=function(n){return n?j.isArray(n)?o.call(n):n.length===+n.length?j.map(n,j.identity):j.values(n):[]},j.size=function(n){return null==n?0:n.length===+n.length?n.length:j.keys(n).length},j.first=j.head=j.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:0>t?[]:o.call(n,0,t)},j.initial=function(n,t,r){return o.call(n,0,n.length-(null==t||r?1:t))},j.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:o.call(n,Math.max(n.length-t,0))},j.rest=j.tail=j.drop=function(n,t,r){return o.call(n,null==t||r?1:t)},j.compact=function(n){return j.filter(n,j.identity)};var M=function(n,t,r){return t&&j.every(n,j.isArray)?c.apply(r,n):(A(n,function(n){j.isArray(n)||j.isArguments(n)?t?a.apply(r,n):M(n,t,r):r.push(n)}),r)};j.flatten=function(n,t){return M(n,t,[])},j.without=function(n){return j.difference(n,o.call(arguments,1))},j.partition=function(n,t){var r=[],e=[];return A(n,function(n){(t(n)?r:e).push(n)}),[r,e]},j.uniq=j.unique=function(n,t,r,e){j.isFunction(t)&&(e=r,r=t,t=!1);var u=r?j.map(n,r,e):n,i=[],a=[];return A(u,function(r,e){(t?e&&a[a.length-1]===r:j.contains(a,r))||(a.push(r),i.push(n[e]))}),i},j.union=function(){return j.uniq(j.flatten(arguments,!0))},j.intersection=function(n){var t=o.call(arguments,1);return j.filter(j.uniq(n),function(n){return j.every(t,function(t){return j.contains(t,n)})})},j.difference=function(n){var t=c.apply(e,o.call(arguments,1));return j.filter(n,function(n){return!j.contains(t,n)})},j.zip=function(){for(var n=j.max(j.pluck(arguments,"length").concat(0)),t=new Array(n),r=0;n>r;r++)t[r]=j.pluck(arguments,""+r);return t},j.object=function(n,t){if(null==n)return{};for(var r={},e=0,u=n.length;u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},j.indexOf=function(n,t,r){if(null==n)return-1;var e=0,u=n.length;if(r){if("number"!=typeof r)return e=j.sortedIndex(n,t),n[e]===t?e:-1;e=0>r?Math.max(0,u+r):r}if(y&&n.indexOf===y)return n.indexOf(t,r);for(;u>e;e++)if(n[e]===t)return e;return-1},j.lastIndexOf=function(n,t,r){if(null==n)return-1;var e=null!=r;if(b&&n.lastIndexOf===b)return e?n.lastIndexOf(t,r):n.lastIndexOf(t);for(var u=e?r:n.length;u--;)if(n[u]===t)return u;return-1},j.range=function(n,t,r){arguments.length<=1&&(t=n||0,n=0),r=arguments[2]||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=0,i=new Array(e);e>u;)i[u++]=n,n+=r;return i};var R=function(){};j.bind=function(n,t){var r,e;if(_&&n.bind===_)return _.apply(n,o.call(arguments,1));if(!j.isFunction(n))throw new TypeError;return r=o.call(arguments,2),e=function(){if(!(this instanceof e))return n.apply(t,r.concat(o.call(arguments)));R.prototype=n.prototype;var u=new R;R.prototype=null;var i=n.apply(u,r.concat(o.call(arguments)));return Object(i)===i?i:u}},j.partial=function(n){var t=o.call(arguments,1);return function(){for(var r=0,e=t.slice(),u=0,i=e.length;i>u;u++)e[u]===j&&(e[u]=arguments[r++]);for(;r<arguments.length;)e.push(arguments[r++]);return n.apply(this,e)}},j.bindAll=function(n){var t=o.call(arguments,1);if(0===t.length)throw new Error("bindAll must be passed function names");return A(t,function(t){n[t]=j.bind(n[t],n)}),n},j.memoize=function(n,t){var r={};return t||(t=j.identity),function(){var e=t.apply(this,arguments);return j.has(r,e)?r[e]:r[e]=n.apply(this,arguments)}},j.delay=function(n,t){var r=o.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},j.defer=function(n){return j.delay.apply(j,[n,1].concat(o.call(arguments,1)))},j.throttle=function(n,t,r){var e,u,i,a=null,o=0;r||(r={});var c=function(){o=r.leading===!1?0:j.now(),a=null,i=n.apply(e,u),e=u=null};return function(){var l=j.now();o||r.leading!==!1||(o=l);var f=t-(l-o);return e=this,u=arguments,0>=f?(clearTimeout(a),a=null,o=l,i=n.apply(e,u),e=u=null):a||r.trailing===!1||(a=setTimeout(c,f)),i}},j.debounce=function(n,t,r){var e,u,i,a,o,c=function(){var l=j.now()-a;t>l?e=setTimeout(c,t-l):(e=null,r||(o=n.apply(i,u),i=u=null))};return function(){i=this,u=arguments,a=j.now();var l=r&&!e;return e||(e=setTimeout(c,t)),l&&(o=n.apply(i,u),i=u=null),o}},j.once=function(n){var t,r=!1;return function(){return r?t:(r=!0,t=n.apply(this,arguments),n=null,t)}},j.wrap=function(n,t){return j.partial(t,n)},j.compose=function(){var n=arguments;return function(){for(var t=arguments,r=n.length-1;r>=0;r--)t=[n[r].apply(this,t)];return t[0]}},j.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},j.keys=function(n){if(!j.isObject(n))return[];if(w)return w(n);var t=[];for(var r in n)j.has(n,r)&&t.push(r);return t},j.values=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},j.pairs=function(n){for(var t=j.keys(n),r=t.length,e=new Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},j.invert=function(n){for(var t={},r=j.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},j.functions=j.methods=function(n){var t=[];for(var r in n)j.isFunction(n[r])&&t.push(r);return t.sort()},j.extend=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]=t[r]}),n},j.pick=function(n){var t={},r=c.apply(e,o.call(arguments,1));return A(r,function(r){r in n&&(t[r]=n[r])}),t},j.omit=function(n){var t={},r=c.apply(e,o.call(arguments,1));for(var u in n)j.contains(r,u)||(t[u]=n[u]);return t},j.defaults=function(n){return A(o.call(arguments,1),function(t){if(t)for(var r in t)n[r]===void 0&&(n[r]=t[r])}),n},j.clone=function(n){return j.isObject(n)?j.isArray(n)?n.slice():j.extend({},n):n},j.tap=function(n,t){return t(n),n};var S=function(n,t,r,e){if(n===t)return 0!==n||1/n==1/t;if(null==n||null==t)return n===t;n instanceof j&&(n=n._wrapped),t instanceof j&&(t=t._wrapped);var u=l.call(n);if(u!=l.call(t))return!1;switch(u){case"[object String]":return n==String(t);case"[object Number]":return n!=+n?t!=+t:0==n?1/n==1/t:n==+t;case"[object Date]":case"[object Boolean]":return+n==+t;case"[object RegExp]":return n.source==t.source&&n.global==t.global&&n.multiline==t.multiline&&n.ignoreCase==t.ignoreCase}if("object"!=typeof n||"object"!=typeof t)return!1;for(var i=r.length;i--;)if(r[i]==n)return e[i]==t;var a=n.constructor,o=t.constructor;if(a!==o&&!(j.isFunction(a)&&a instanceof a&&j.isFunction(o)&&o instanceof o)&&"constructor"in n&&"constructor"in t)return!1;r.push(n),e.push(t);var c=0,f=!0;if("[object Array]"==u){if(c=n.length,f=c==t.length)for(;c--&&(f=S(n[c],t[c],r,e)););}else{for(var s in n)if(j.has(n,s)&&(c++,!(f=j.has(t,s)&&S(n[s],t[s],r,e))))break;if(f){for(s in t)if(j.has(t,s)&&!c--)break;f=!c}}return r.pop(),e.pop(),f};j.isEqual=function(n,t){return S(n,t,[],[])},j.isEmpty=function(n){if(null==n)return!0;if(j.isArray(n)||j.isString(n))return 0===n.length;for(var t in n)if(j.has(n,t))return!1;return!0},j.isElement=function(n){return!(!n||1!==n.nodeType)},j.isArray=x||function(n){return"[object Array]"==l.call(n)},j.isObject=function(n){return n===Object(n)},A(["Arguments","Function","String","Number","Date","RegExp"],function(n){j["is"+n]=function(t){return l.call(t)=="[object "+n+"]"}}),j.isArguments(arguments)||(j.isArguments=function(n){return!(!n||!j.has(n,"callee"))}),"function"!=typeof/./&&(j.isFunction=function(n){return"function"==typeof n}),j.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},j.isNaN=function(n){return j.isNumber(n)&&n!=+n},j.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"==l.call(n)},j.isNull=function(n){return null===n},j.isUndefined=function(n){return n===void 0},j.has=function(n,t){return f.call(n,t)},j.noConflict=function(){return n._=t,this},j.identity=function(n){return n},j.constant=function(n){return function(){return n}},j.property=function(n){return function(t){return t[n]}},j.matches=function(n){return function(t){if(t===n)return!0;for(var r in n)if(n[r]!==t[r])return!1;return!0}},j.times=function(n,t,r){for(var e=Array(Math.max(0,n)),u=0;n>u;u++)e[u]=t.call(r,u);return e},j.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},j.now=Date.now||function(){return(new Date).getTime()};var T={escape:{"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;"}};T.unescape=j.invert(T.escape);var I={escape:new RegExp("["+j.keys(T.escape).join("")+"]","g"),unescape:new RegExp("("+j.keys(T.unescape).join("|")+")","g")};j.each(["escape","unescape"],function(n){j[n]=function(t){return null==t?"":(""+t).replace(I[n],function(t){return T[n][t]})}}),j.result=function(n,t){if(null==n)return void 0;var r=n[t];return j.isFunction(r)?r.call(n):r},j.mixin=function(n){A(j.functions(n),function(t){var r=j[t]=n[t];j.prototype[t]=function(){var n=[this._wrapped];return a.apply(n,arguments),z.call(this,r.apply(j,n))}})};var N=0;j.uniqueId=function(n){var t=++N+"";return n?n+t:t},j.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var q=/(.)^/,B={"'":"'","\\":"\\","\r":"r","\n":"n","   ":"t","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\t|\u2028|\u2029/g;j.template=function(n,t,r){var e;r=j.defaults({},r,j.templateSettings);var u=new RegExp([(r.escape||q).source,(r.interpolate||q).source,(r.evaluate||q).source].join("|")+"|$","g"),i=0,a="__p+='";n.replace(u,function(t,r,e,u,o){return a+=n.slice(i,o).replace(D,function(n){return"\\"+B[n]}),r&&(a+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'"),e&&(a+="'+\n((__t=("+e+"))==null?'':__t)+\n'"),u&&(a+="';\n"+u+"\n__p+='"),i=o+t.length,t}),a+="';\n",r.variable||(a="with(obj||{}){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{e=new Function(r.variable||"obj","_",a)}catch(o){throw o.source=a,o}if(t)return e(t,j);var c=function(n){return e.call(this,n,j)};return c.source="function("+(r.variable||"obj")+"){\n"+a+"}",c},j.chain=function(n){return j(n).chain()};var z=function(n){return this._chain?j(n).chain():n};j.mixin(j),A(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=e[n];j.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!=n&&"splice"!=n||0!==r.length||delete r[0],z.call(this,r)}}),A(["concat","join","slice"],function(n){var t=e[n];j.prototype[n]=function(){return z.call(this,t.apply(this._wrapped,arguments))}}),j.extend(j.prototype,{chain:function(){return this._chain=!0,this},value:function(){return this._wrapped}}),"function"==typeof define&&define.amd&&define("underscore",[],function(){return j})}).call(this);
     5(function(){function n(n){function t(t,r,e,u,i,o){for(;i>=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])<u?i=a+1:o=a}return i},m.indexOf=r(1,m.findIndex,m.sortedIndex),m.lastIndexOf=r(-1,m.findLastIndex),m.range=function(n,t,r){null==t&&(t=n||0,n=0),r=r||1;for(var e=Math.max(Math.ceil((t-n)/r),0),u=Array(e),i=0;e>i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e<arguments.length;)i.push(arguments[e++]);return E(n,r,this,this,i)};return r},m.bindAll=function(n){var t,r,e=arguments.length;if(1>=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","`":"&#x60;"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this);
  • trunk/src/wp-includes/script-loader.php

    r36510 r36546  
    315315    did_action( 'init' ) && $scripts->add_data( 'json2', 'conditional', 'lt IE 8' );
    316316
    317     $scripts->add( 'underscore', "/wp-includes/js/underscore$dev_suffix.js", array(), '1.6.0', 1 );
    318     $scripts->add( 'backbone', "/wp-includes/js/backbone$dev_suffix.js", array( 'underscore','jquery' ), '1.1.2', 1 );
     317    $scripts->add( 'underscore', "/wp-includes/js/underscore$dev_suffix.js", array(), '1.8.3', 1 );
     318    $scripts->add( 'backbone', "/wp-includes/js/backbone$dev_suffix.js", array( 'underscore','jquery' ), '1.2.3', 1 );
    319319
    320320    $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array('underscore', 'jquery'), false, 1 );
Note: See TracChangeset for help on using the changeset viewer.