<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[36546] trunk/src: Update Backbone and Underscore to the latest versions.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/36546">36546</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/36546","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>ocean90</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2016-02-17 15:21:09 +0000 (Wed, 17 Feb 2016)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>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 [http://backbonejs.org/#changelog Backbone changelog] and [http://underscorejs.org/#changelog 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 [https://github.com/jashkenas/underscore/issues/1904#issuecomment-60241576 underscore<a href="https://core.trac.wordpress.org/ticket/1904">#1904</a>]. 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 <a href="https://core.trac.wordpress.org/ticket/34350">#34350</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminjscustomizewidgetsjs">trunk/src/wp-admin/js/customize-widgets.js</a></li>
<li><a href="#trunksrcwpincludesjsbackbonejs">trunk/src/wp-includes/js/backbone.js</a></li>
<li><a href="#trunksrcwpincludesjsbackboneminjs">trunk/src/wp-includes/js/backbone.min.js</a></li>
<li><a href="#trunksrcwpincludesjsmediaviewsmediadetailsjs">trunk/src/wp-includes/js/media/views/media-details.js</a></li>
<li><a href="#trunksrcwpincludesjsmediaaudiovideojs">trunk/src/wp-includes/js/media-audiovideo.js</a></li>
<li><a href="#trunksrcwpincludesjsunderscorejs">trunk/src/wp-includes/js/underscore.js</a></li>
<li><a href="#trunksrcwpincludesjsunderscoreminjs">trunk/src/wp-includes/js/underscore.min.js</a></li>
<li><a href="#trunksrcwpincludesscriptloaderphp">trunk/src/wp-includes/script-loader.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminjscustomizewidgetsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-admin/js/customize-widgets.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-admin/js/customize-widgets.js        2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-admin/js/customize-widgets.js  2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -663,7 +663,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                 */
</span><span class="cx" style="display: block; padding: 0 10px">                _setupReorderUI: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var self = this, selectSidebarItem, $moveWidgetArea,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                $reorderNav, updateAvailableSidebars;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         $reorderNav, updateAvailableSidebars, template;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        /**
</span><span class="cx" style="display: block; padding: 0 10px">                         * select the provided sidebar list item in the move widget area
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -681,8 +681,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">                         * Add the widget reordering elements to the widget control
</span><span class="cx" style="display: block; padding: 0 10px">                         */
</span><span class="cx" style="display: block; padding: 0 10px">                        this.container.find( '.widget-title-action' ).after( $( api.Widgets.data.tpl.widgetReorderNav ) );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $moveWidgetArea = $(
-                               _.template( api.Widgets.data.tpl.moveWidgetArea, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+
+                       template = _.template( api.Widgets.data.tpl.moveWidgetArea );
+                       $moveWidgetArea = $( template( {
</ins><span class="cx" style="display: block; padding: 0 10px">                                         sidebars: _( api.Widgets.registeredSidebars.toArray() ).pluck( 'attributes' )
</span><span class="cx" style="display: block; padding: 0 10px">                                } )
</span><span class="cx" style="display: block; padding: 0 10px">                        );
</span></span></pre></div>
<a id="trunksrcwpincludesjsbackbonejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/backbone.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/backbone.js      2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/js/backbone.js        2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,12 +1,17 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//     Backbone.js 1.1.2
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+//     Backbone.js 1.2.3
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//     (c) 2010-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+//     (c) 2010-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
</ins><span class="cx" style="display: block; padding: 0 10px"> //     Backbone may be freely distributed under the MIT license.
</span><span class="cx" style="display: block; padding: 0 10px"> //     For all details and documentation:
</span><span class="cx" style="display: block; padding: 0 10px"> //     http://backbonejs.org
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-(function(root, factory) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+(function(factory) {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Establish the root object, `window` (`self`) in the browser, or `global` on the server.
+  // We use `self` instead of `window` for `WebWorker` support.
+  var root = (typeof self == 'object' && self.self == self && self) ||
+            (typeof global == 'object' && global.global == global && global);
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Set up Backbone appropriately for the environment. Start with AMD.
</span><span class="cx" style="display: block; padding: 0 10px">   if (typeof define === 'function' && define.amd) {
</span><span class="cx" style="display: block; padding: 0 10px">     define(['underscore', 'jquery', 'exports'], function(_, $, exports) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -17,15 +22,16 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Next for Node.js or CommonJS. jQuery may not be needed as a module.
</span><span class="cx" style="display: block; padding: 0 10px">   } else if (typeof exports !== 'undefined') {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var _ = require('underscore');
-    factory(root, exports, _);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var _ = require('underscore'), $;
+    try { $ = require('jquery'); } catch(e) {}
+    factory(root, exports, _, $);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Finally, as a browser global.
</span><span class="cx" style="display: block; padding: 0 10px">   } else {
</span><span class="cx" style="display: block; padding: 0 10px">     root.Backbone = factory(root, {}, root._, (root.jQuery || root.Zepto || root.ender || root.$));
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-}(this, function(root, Backbone, _, $) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+}(function(root, Backbone, _, $) {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Initial Setup
</span><span class="cx" style="display: block; padding: 0 10px">   // -------------
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -34,14 +40,11 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // restored later on, if `noConflict` is used.
</span><span class="cx" style="display: block; padding: 0 10px">   var previousBackbone = root.Backbone;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Create local references to array methods we'll want to use later.
-  var array = [];
-  var push = array.push;
-  var slice = array.slice;
-  var splice = array.splice;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Create a local reference to a common array method we'll want to use later.
+  var slice = Array.prototype.slice;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Current version of the library. Keep in sync with `package.json`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  Backbone.VERSION = '1.1.2';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  Backbone.VERSION = '1.2.3';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // For Backbone's purposes, jQuery, Zepto, Ender, or My Library (kidding) owns
</span><span class="cx" style="display: block; padding: 0 10px">   // the `$` variable.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -60,17 +63,65 @@
</span><span class="cx" style="display: block; padding: 0 10px">   Backbone.emulateHTTP = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Turn on `emulateJSON` to support legacy servers that can't deal with direct
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // `application/json` requests ... will encode the body as
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // `application/json` requests ... this will encode the body as
</ins><span class="cx" style="display: block; padding: 0 10px">   // `application/x-www-form-urlencoded` instead and will send the model in a
</span><span class="cx" style="display: block; padding: 0 10px">   // form param named `model`.
</span><span class="cx" style="display: block; padding: 0 10px">   Backbone.emulateJSON = false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Proxy Backbone class methods to Underscore functions, wrapping the model's
+  // `attributes` object or collection's `models` array behind the scenes.
+  //
+  // collection.filter(function(model) { return model.get('age') > 10 });
+  // collection.each(this.addView);
+  //
+  // `Function#apply` can be slow so we use the method's arg count, if we know it.
+  var addMethod = function(length, method, attribute) {
+    switch (length) {
+      case 1: return function() {
+        return _[method](this[attribute]);
+      };
+      case 2: return function(value) {
+        return _[method](this[attribute], value);
+      };
+      case 3: return function(iteratee, context) {
+        return _[method](this[attribute], cb(iteratee, this), context);
+      };
+      case 4: return function(iteratee, defaultVal, context) {
+        return _[method](this[attribute], cb(iteratee, this), defaultVal, context);
+      };
+      default: return function() {
+        var args = slice.call(arguments);
+        args.unshift(this[attribute]);
+        return _[method].apply(_, args);
+      };
+    }
+  };
+  var addUnderscoreMethods = function(Class, methods, attribute) {
+    _.each(methods, function(length, method) {
+      if (_[method]) Class.prototype[method] = addMethod(length, method, attribute);
+    });
+  };
+
+  // Support `collection.sortBy('attr')` and `collection.findWhere({id: 1})`.
+  var cb = function(iteratee, instance) {
+    if (_.isFunction(iteratee)) return iteratee;
+    if (_.isObject(iteratee) && !instance._isModel(iteratee)) return modelMatcher(iteratee);
+    if (_.isString(iteratee)) return function(model) { return model.get(iteratee); };
+    return iteratee;
+  };
+  var modelMatcher = function(attrs) {
+    var matcher = _.matches(attrs);
+    return function(model) {
+      return matcher(model.attributes);
+    };
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Backbone.Events
</span><span class="cx" style="display: block; padding: 0 10px">   // ---------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // A module that can be mixed in to *any object* in order to provide it with
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // custom events. You may bind with `on` or remove with `off` callback
-  // functions to an event; `trigger`-ing an event fires all callbacks in
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // a custom event channel. You may bind a callback to an event with `on` or
+  // remove with `off`; `trigger`-ing an event fires all callbacks in
</ins><span class="cx" style="display: block; padding: 0 10px">   // succession.
</span><span class="cx" style="display: block; padding: 0 10px">   //
</span><span class="cx" style="display: block; padding: 0 10px">   //     var object = {};
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -78,125 +129,236 @@
</span><span class="cx" style="display: block; padding: 0 10px">   //     object.on('expand', function(){ alert('expanded'); });
</span><span class="cx" style="display: block; padding: 0 10px">   //     object.trigger('expand');
</span><span class="cx" style="display: block; padding: 0 10px">   //
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var Events = Backbone.Events = {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var Events = Backbone.Events = {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Bind an event to a `callback` function. Passing `"all"` will bind
-    // the callback to all events fired.
-    on: function(name, callback, context) {
-      if (!eventsApi(this, 'on', name, [callback, context]) || !callback) return this;
-      this._events || (this._events = {});
-      var events = this._events[name] || (this._events[name] = []);
-      events.push({callback: callback, context: context, ctx: context || this});
-      return this;
-    },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Regular expression used to split event strings.
+  var eventSplitter = /\s+/;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Bind an event to only be triggered a single time. After the first time
-    // the callback is invoked, it will be removed.
-    once: function(name, callback, context) {
-      if (!eventsApi(this, 'once', name, [callback, context]) || !callback) return this;
-      var self = this;
-      var once = _.once(function() {
-        self.off(name, once);
-        callback.apply(this, arguments);
-      });
-      once._callback = callback;
-      return this.on(name, once, context);
-    },
-
-    // Remove one or many callbacks. If `context` is null, removes all
-    // callbacks with that function. If `callback` is null, removes all
-    // callbacks for the event. If `name` is null, removes all bound
-    // callbacks for all events.
-    off: function(name, callback, context) {
-      var retain, ev, events, names, i, l, j, k;
-      if (!this._events || !eventsApi(this, 'off', name, [callback, context])) return this;
-      if (!name && !callback && !context) {
-        this._events = void 0;
-        return this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Iterates over the standard `event, callback` (as well as the fancy multiple
+  // space-separated events `"change blur", callback` and jQuery-style event
+  // maps `{event: callback}`).
+  var eventsApi = function(iteratee, events, name, callback, opts) {
+    var i = 0, names;
+    if (name && typeof name === 'object') {
+      // Handle event maps.
+      if (callback !== void 0 && 'context' in opts && opts.context === void 0) opts.context = callback;
+      for (names = _.keys(name); i < names.length ; i++) {
+        events = eventsApi(iteratee, events, names[i], name[names[i]], opts);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      names = name ? [name] : _.keys(this._events);
-      for (i = 0, l = names.length; i < l; i++) {
-        name = names[i];
-        if (events = this._events[name]) {
-          this._events[name] = retain = [];
-          if (callback || context) {
-            for (j = 0, k = events.length; j < k; j++) {
-              ev = events[j];
-              if ((callback && callback !== ev.callback && callback !== ev.callback._callback) ||
-                  (context && context !== ev.context)) {
-                retain.push(ev);
-              }
-            }
-          }
-          if (!retain.length) delete this._events[name];
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    } else if (name && eventSplitter.test(name)) {
+      // Handle space separated event names by delegating them individually.
+      for (names = name.split(eventSplitter); i < names.length; i++) {
+        events = iteratee(events, names[i], callback, opts);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    } else {
+      // Finally, standard events.
+      events = iteratee(events, name, callback, opts);
+    }
+    return events;
+  };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return this;
-    },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Bind an event to a `callback` function. Passing `"all"` will bind
+  // the callback to all events fired.
+  Events.on = function(name, callback, context) {
+    return internalOn(this, name, callback, context);
+  };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Trigger one or many events, firing all bound callbacks. Callbacks are
-    // passed the same arguments as `trigger` is, apart from the event name
-    // (unless you're listening on `"all"`, which will cause your callback to
-    // receive the true name of the event as the first argument).
-    trigger: function(name) {
-      if (!this._events) return this;
-      var args = slice.call(arguments, 1);
-      if (!eventsApi(this, 'trigger', name, args)) return this;
-      var events = this._events[name];
-      var allEvents = this._events.all;
-      if (events) triggerEvents(events, args);
-      if (allEvents) triggerEvents(allEvents, arguments);
-      return this;
-    },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Guard the `listening` argument from the public API.
+  var internalOn = function(obj, name, callback, context, listening) {
+    obj._events = eventsApi(onApi, obj._events || {}, name, callback, {
+        context: context,
+        ctx: obj,
+        listening: listening
+    });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Tell this object to stop listening to either specific events ... or
-    // to every object it's currently listening to.
-    stopListening: function(obj, name, callback) {
-      var listeningTo = this._listeningTo;
-      if (!listeningTo) return this;
-      var remove = !name && !callback;
-      if (!callback && typeof name === 'object') callback = this;
-      if (obj) (listeningTo = {})[obj._listenId] = obj;
-      for (var id in listeningTo) {
-        obj = listeningTo[id];
-        obj.off(name, callback, this);
-        if (remove || _.isEmpty(obj._events)) delete this._listeningTo[id];
-      }
-      return this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (listening) {
+      var listeners = obj._listeners || (obj._listeners = {});
+      listeners[listening.id] = listening;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return obj;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Regular expression used to split event strings.
-  var eventSplitter = /\s+/;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Inversion-of-control versions of `on`. Tell *this* object to listen to
+  // an event in another object... keeping track of what it's listening to
+  // for easier unbinding later.
+  Events.listenTo =  function(obj, name, callback) {
+    if (!obj) return this;
+    var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
+    var listeningTo = this._listeningTo || (this._listeningTo = {});
+    var listening = listeningTo[id];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Implement fancy features of the Events API such as multiple event
-  // names `"change blur"` and jQuery-style event maps `{change: action}`
-  // in terms of the existing API.
-  var eventsApi = function(obj, action, name, rest) {
-    if (!name) return true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // This object is not listening to any other events on `obj` yet.
+    // Setup the necessary references to track the listening callbacks.
+    if (!listening) {
+      var thisId = this._listenId || (this._listenId = _.uniqueId('l'));
+      listening = listeningTo[id] = {obj: obj, objId: id, id: thisId, listeningTo: listeningTo, count: 0};
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Handle event maps.
-    if (typeof name === 'object') {
-      for (var key in name) {
-        obj[action].apply(obj, [key, name[key]].concat(rest));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Bind callbacks on obj, and keep track of them on listening.
+    internalOn(obj, name, callback, this, listening);
+    return this;
+  };
+
+  // The reducing API that adds a callback to the `events` object.
+  var onApi = function(events, name, callback, options) {
+    if (callback) {
+      var handlers = events[name] || (events[name] = []);
+      var context = options.context, ctx = options.ctx, listening = options.listening;
+      if (listening) listening.count++;
+
+      handlers.push({ callback: callback, context: context, ctx: context || ctx, listening: listening });
+    }
+    return events;
+  };
+
+  // Remove one or many callbacks. If `context` is null, removes all
+  // callbacks with that function. If `callback` is null, removes all
+  // callbacks for the event. If `name` is null, removes all bound
+  // callbacks for all events.
+  Events.off =  function(name, callback, context) {
+    if (!this._events) return this;
+    this._events = eventsApi(offApi, this._events, name, callback, {
+        context: context,
+        listeners: this._listeners
+    });
+    return this;
+  };
+
+  // Tell this object to stop listening to either specific events ... or
+  // to every object it's currently listening to.
+  Events.stopListening =  function(obj, name, callback) {
+    var listeningTo = this._listeningTo;
+    if (!listeningTo) return this;
+
+    var ids = obj ? [obj._listenId] : _.keys(listeningTo);
+
+    for (var i = 0; i < ids.length; i++) {
+      var listening = listeningTo[ids[i]];
+
+      // If listening doesn't exist, this object is not currently
+      // listening to obj. Break out early.
+      if (!listening) break;
+
+      listening.obj.off(name, callback, this);
+    }
+    if (_.isEmpty(listeningTo)) this._listeningTo = void 0;
+
+    return this;
+  };
+
+  // The reducing API that removes a callback from the `events` object.
+  var offApi = function(events, name, callback, options) {
+    if (!events) return;
+
+    var i = 0, listening;
+    var context = options.context, listeners = options.listeners;
+
+    // Delete all events listeners and "drop" events.
+    if (!name && !callback && !context) {
+      var ids = _.keys(listeners);
+      for (; i < ids.length; i++) {
+        listening = listeners[ids[i]];
+        delete listeners[listening.id];
+        delete listening.listeningTo[listening.objId];
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Handle space separated event names.
-    if (eventSplitter.test(name)) {
-      var names = name.split(eventSplitter);
-      for (var i = 0, l = names.length; i < l; i++) {
-        obj[action].apply(obj, [names[i]].concat(rest));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var names = name ? [name] : _.keys(events);
+    for (; i < names.length; i++) {
+      name = names[i];
+      var handlers = events[name];
+
+      // Bail out if there are no events stored.
+      if (!handlers) break;
+
+      // Replace events if there are any remaining.  Otherwise, clean up.
+      var remaining = [];
+      for (var j = 0; j < handlers.length; j++) {
+        var handler = handlers[j];
+        if (
+          callback && callback !== handler.callback &&
+            callback !== handler.callback._callback ||
+              context && context !== handler.context
+        ) {
+          remaining.push(handler);
+        } else {
+          listening = handler.listening;
+          if (listening && --listening.count === 0) {
+            delete listeners[listening.id];
+            delete listening.listeningTo[listening.objId];
+          }
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      // Update tail event if the list has any events.  Otherwise, clean up.
+      if (remaining.length) {
+        events[name] = remaining;
+      } else {
+        delete events[name];
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (_.size(events)) return events;
+  };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Bind an event to only be triggered a single time. After the first time
+  // the callback is invoked, its listener will be removed. If multiple events
+  // are passed in using the space-separated syntax, the handler will fire
+  // once for each event, not once for a combination of all events.
+  Events.once =  function(name, callback, context) {
+    // Map the event into a `{event: once}` object.
+    var events = eventsApi(onceMap, {}, name, callback, _.bind(this.off, this));
+    return this.on(events, void 0, context);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Inversion-of-control versions of `once`.
+  Events.listenToOnce =  function(obj, name, callback) {
+    // Map the event into a `{event: once}` object.
+    var events = eventsApi(onceMap, {}, name, callback, _.bind(this.stopListening, this, obj));
+    return this.listenTo(obj, events);
+  };
+
+  // Reduces the event callbacks into a map of `{event: onceWrapper}`.
+  // `offer` unbinds the `onceWrapper` after it has been called.
+  var onceMap = function(map, name, callback, offer) {
+    if (callback) {
+      var once = map[name] = _.once(function() {
+        offer(name, once);
+        callback.apply(this, arguments);
+      });
+      once._callback = callback;
+    }
+    return map;
+  };
+
+  // Trigger one or many events, firing all bound callbacks. Callbacks are
+  // passed the same arguments as `trigger` is, apart from the event name
+  // (unless you're listening on `"all"`, which will cause your callback to
+  // receive the true name of the event as the first argument).
+  Events.trigger =  function(name) {
+    if (!this._events) return this;
+
+    var length = Math.max(0, arguments.length - 1);
+    var args = Array(length);
+    for (var i = 0; i < length; i++) args[i] = arguments[i + 1];
+
+    eventsApi(triggerApi, this._events, name, void 0, args);
+    return this;
+  };
+
+  // Handles triggering the appropriate event callbacks.
+  var triggerApi = function(objEvents, name, cb, args) {
+    if (objEvents) {
+      var events = objEvents[name];
+      var allEvents = objEvents.all;
+      if (events && allEvents) allEvents = allEvents.slice();
+      if (events) triggerEvents(events, args);
+      if (allEvents) triggerEvents(allEvents, [name].concat(args));
+    }
+    return objEvents;
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // A difficult-to-believe, but optimized internal dispatch function for
</span><span class="cx" style="display: block; padding: 0 10px">   // triggering events. Tries to keep the usual cases speedy (most internal
</span><span class="cx" style="display: block; padding: 0 10px">   // Backbone events have 3 arguments).
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -211,22 +373,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var listenMethods = {listenTo: 'on', listenToOnce: 'once'};
-
-  // Inversion-of-control versions of `on` and `once`. Tell *this* object to
-  // listen to an event in another object ... keeping track of what it's
-  // listening to.
-  _.each(listenMethods, function(implementation, method) {
-    Events[method] = function(obj, name, callback) {
-      var listeningTo = this._listeningTo || (this._listeningTo = {});
-      var id = obj._listenId || (obj._listenId = _.uniqueId('l'));
-      listeningTo[id] = obj;
-      if (!callback && typeof name === 'object') callback = this;
-      obj[implementation](name, callback, this);
-      return this;
-    };
-  });
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Aliases for backwards compatibility.
</span><span class="cx" style="display: block; padding: 0 10px">   Events.bind   = Events.on;
</span><span class="cx" style="display: block; padding: 0 10px">   Events.unbind = Events.off;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -248,7 +394,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   var Model = Backbone.Model = function(attributes, options) {
</span><span class="cx" style="display: block; padding: 0 10px">     var attrs = attributes || {};
</span><span class="cx" style="display: block; padding: 0 10px">     options || (options = {});
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    this.cid = _.uniqueId('c');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    this.cid = _.uniqueId(this.cidPrefix);
</ins><span class="cx" style="display: block; padding: 0 10px">     this.attributes = {};
</span><span class="cx" style="display: block; padding: 0 10px">     if (options.collection) this.collection = options.collection;
</span><span class="cx" style="display: block; padding: 0 10px">     if (options.parse) attrs = this.parse(attrs, options) || {};
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -271,6 +417,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // CouchDB users may want to set this to `"_id"`.
</span><span class="cx" style="display: block; padding: 0 10px">     idAttribute: 'id',
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // The prefix is used to create the client id which is used to identify models locally.
+    // You may want to override this if you're experiencing name clashes with model ids.
+    cidPrefix: 'c',
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Initialize is an empty function by default. Override it with your own
</span><span class="cx" style="display: block; padding: 0 10px">     // initialization logic.
</span><span class="cx" style="display: block; padding: 0 10px">     initialize: function(){},
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -302,14 +452,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return this.get(attr) != null;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Special-cased proxy to underscore's `_.matches` method.
+    matches: function(attrs) {
+      return !!_.iteratee(attrs, this)(this.attributes);
+    },
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Set a hash of model attributes on the object, firing `"change"`. This is
</span><span class="cx" style="display: block; padding: 0 10px">     // the core primitive operation of a model, updating the data and notifying
</span><span class="cx" style="display: block; padding: 0 10px">     // anyone who needs to know about the change in state. The heart of the beast.
</span><span class="cx" style="display: block; padding: 0 10px">     set: function(key, val, options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var attr, attrs, unset, changes, silent, changing, prev, current;
</del><span class="cx" style="display: block; padding: 0 10px">       if (key == null) return this;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Handle both `"key", value` and `{key: value}` -style arguments.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var attrs;
</ins><span class="cx" style="display: block; padding: 0 10px">       if (typeof key === 'object') {
</span><span class="cx" style="display: block; padding: 0 10px">         attrs = key;
</span><span class="cx" style="display: block; padding: 0 10px">         options = val;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -323,37 +478,40 @@
</span><span class="cx" style="display: block; padding: 0 10px">       if (!this._validate(attrs, options)) return false;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Extract attributes and options.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      unset           = options.unset;
-      silent          = options.silent;
-      changes         = [];
-      changing        = this._changing;
-      this._changing  = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var unset      = options.unset;
+      var silent     = options.silent;
+      var changes    = [];
+      var changing   = this._changing;
+      this._changing = true;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (!changing) {
</span><span class="cx" style="display: block; padding: 0 10px">         this._previousAttributes = _.clone(this.attributes);
</span><span class="cx" style="display: block; padding: 0 10px">         this.changed = {};
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      current = this.attributes, prev = this._previousAttributes;
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Check for changes of `id`.
-      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var current = this.attributes;
+      var changed = this.changed;
+      var prev    = this._previousAttributes;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // For each `set` attribute, update or delete the current value.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (attr in attrs) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      for (var attr in attrs) {
</ins><span class="cx" style="display: block; padding: 0 10px">         val = attrs[attr];
</span><span class="cx" style="display: block; padding: 0 10px">         if (!_.isEqual(current[attr], val)) changes.push(attr);
</span><span class="cx" style="display: block; padding: 0 10px">         if (!_.isEqual(prev[attr], val)) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          this.changed[attr] = val;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          changed[attr] = val;
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          delete this.changed[attr];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          delete changed[attr];
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">         unset ? delete current[attr] : current[attr] = val;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Update the `id`.
+      this.id = this.get(this.idAttribute);
+
</ins><span class="cx" style="display: block; padding: 0 10px">       // Trigger all relevant attribute changes.
</span><span class="cx" style="display: block; padding: 0 10px">       if (!silent) {
</span><span class="cx" style="display: block; padding: 0 10px">         if (changes.length) this._pending = options;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        for (var i = 0, l = changes.length; i < l; i++) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (var i = 0; i < changes.length; i++) {
</ins><span class="cx" style="display: block; padding: 0 10px">           this.trigger('change:' + changes[i], this, current[changes[i]], options);
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -401,13 +559,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // determining if there *would be* a change.
</span><span class="cx" style="display: block; padding: 0 10px">     changedAttributes: function(diff) {
</span><span class="cx" style="display: block; padding: 0 10px">       if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var val, changed = false;
</del><span class="cx" style="display: block; padding: 0 10px">       var old = this._changing ? this._previousAttributes : this.attributes;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var changed = {};
</ins><span class="cx" style="display: block; padding: 0 10px">       for (var attr in diff) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (_.isEqual(old[attr], (val = diff[attr]))) continue;
-        (changed || (changed = {}))[attr] = val;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var val = diff[attr];
+        if (_.isEqual(old[attr], val)) continue;
+        changed[attr] = val;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return changed;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return _.size(changed) ? changed : false;
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Get the previous value of an attribute, recorded at the time the last
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -423,17 +582,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return _.clone(this._previousAttributes);
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Fetch the model from the server. If the server's representation of the
-    // model differs from its current attributes, they will be overridden,
-    // triggering a `"change"` event.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Fetch the model from the server, merging the response with the model's
+    // local attributes. Any changed attributes will trigger a "change" event.
</ins><span class="cx" style="display: block; padding: 0 10px">     fetch: function(options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      options = options ? _.clone(options) : {};
-      if (options.parse === void 0) options.parse = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      options = _.extend({parse: true}, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       var model = this;
</span><span class="cx" style="display: block; padding: 0 10px">       var success = options.success;
</span><span class="cx" style="display: block; padding: 0 10px">       options.success = function(resp) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!model.set(model.parse(resp, options), options)) return false;
-        if (success) success(model, resp, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var serverAttrs = options.parse ? model.parse(resp, options) : resp;
+        if (!model.set(serverAttrs, options)) return false;
+        if (success) success.call(options.context, model, resp, options);
</ins><span class="cx" style="display: block; padding: 0 10px">         model.trigger('sync', model, resp, options);
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px">       wrapError(this, options);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -444,9 +602,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // If the server returns an attributes hash that differs, the model's
</span><span class="cx" style="display: block; padding: 0 10px">     // state will be `set` again.
</span><span class="cx" style="display: block; padding: 0 10px">     save: function(key, val, options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var attrs, method, xhr, attributes = this.attributes;
-
</del><span class="cx" style="display: block; padding: 0 10px">       // Handle both `"key", value` and `{key: value}` -style arguments.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var attrs;
</ins><span class="cx" style="display: block; padding: 0 10px">       if (key == null || typeof key === 'object') {
</span><span class="cx" style="display: block; padding: 0 10px">         attrs = key;
</span><span class="cx" style="display: block; padding: 0 10px">         options = val;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -454,46 +611,43 @@
</span><span class="cx" style="display: block; padding: 0 10px">         (attrs = {})[key] = val;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      options = _.extend({validate: true}, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      options = _.extend({validate: true, parse: true}, options);
+      var wait = options.wait;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // If we're not waiting and attributes exist, save acts as
</span><span class="cx" style="display: block; padding: 0 10px">       // `set(attr).save(null, opts)` with validation. Otherwise, check if
</span><span class="cx" style="display: block; padding: 0 10px">       // the model will be valid when the attributes, if any, are set.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (attrs && !options.wait) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (attrs && !wait) {
</ins><span class="cx" style="display: block; padding: 0 10px">         if (!this.set(attrs, options)) return false;
</span><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><span class="cx" style="display: block; padding: 0 10px">         if (!this._validate(attrs, options)) return false;
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Set temporary attributes if `{wait: true}`.
-      if (attrs && options.wait) {
-        this.attributes = _.extend({}, attributes, attrs);
-      }
-
</del><span class="cx" style="display: block; padding: 0 10px">       // After a successful server-side save, the client is (optionally)
</span><span class="cx" style="display: block; padding: 0 10px">       // updated with the server-side state.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (options.parse === void 0) options.parse = true;
</del><span class="cx" style="display: block; padding: 0 10px">       var model = this;
</span><span class="cx" style="display: block; padding: 0 10px">       var success = options.success;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var attributes = this.attributes;
</ins><span class="cx" style="display: block; padding: 0 10px">       options.success = function(resp) {
</span><span class="cx" style="display: block; padding: 0 10px">         // Ensure attributes are restored during synchronous saves.
</span><span class="cx" style="display: block; padding: 0 10px">         model.attributes = attributes;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var serverAttrs = model.parse(resp, options);
-        if (options.wait) serverAttrs = _.extend(attrs || {}, serverAttrs);
-        if (_.isObject(serverAttrs) && !model.set(serverAttrs, options)) {
-          return false;
-        }
-        if (success) success(model, resp, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var serverAttrs = options.parse ? model.parse(resp, options) : resp;
+        if (wait) serverAttrs = _.extend({}, attrs, serverAttrs);
+        if (serverAttrs && !model.set(serverAttrs, options)) return false;
+        if (success) success.call(options.context, model, resp, options);
</ins><span class="cx" style="display: block; padding: 0 10px">         model.trigger('sync', model, resp, options);
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px">       wrapError(this, options);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
-      if (method === 'patch') options.attrs = attrs;
-      xhr = this.sync(method, this, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Set temporary attributes if `{wait: true}` to properly find new ids.
+      if (attrs && wait) this.attributes = _.extend({}, attributes, attrs);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var method = this.isNew() ? 'create' : (options.patch ? 'patch' : 'update');
+      if (method === 'patch' && !options.attrs) options.attrs = attrs;
+      var xhr = this.sync(method, this, options);
+
</ins><span class="cx" style="display: block; padding: 0 10px">       // Restore attributes.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (attrs && options.wait) this.attributes = attributes;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      this.attributes = attributes;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       return xhr;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -505,25 +659,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">       options = options ? _.clone(options) : {};
</span><span class="cx" style="display: block; padding: 0 10px">       var model = this;
</span><span class="cx" style="display: block; padding: 0 10px">       var success = options.success;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var wait = options.wait;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       var destroy = function() {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        model.stopListening();
</ins><span class="cx" style="display: block; padding: 0 10px">         model.trigger('destroy', model, model.collection, options);
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       options.success = function(resp) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (options.wait || model.isNew()) destroy();
-        if (success) success(model, resp, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (wait) destroy();
+        if (success) success.call(options.context, model, resp, options);
</ins><span class="cx" style="display: block; padding: 0 10px">         if (!model.isNew()) model.trigger('sync', model, resp, options);
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var xhr = false;
</ins><span class="cx" style="display: block; padding: 0 10px">       if (this.isNew()) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        options.success();
-        return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        _.defer(options.success);
+      } else {
+        wrapError(this, options);
+        xhr = this.sync('delete', this, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      wrapError(this, options);
-
-      var xhr = this.sync('delete', this, options);
-      if (!options.wait) destroy();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!wait) destroy();
</ins><span class="cx" style="display: block; padding: 0 10px">       return xhr;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -536,7 +692,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">         _.result(this.collection, 'url') ||
</span><span class="cx" style="display: block; padding: 0 10px">         urlError();
</span><span class="cx" style="display: block; padding: 0 10px">       if (this.isNew()) return base;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return base.replace(/([^\/])$/, '$1/') + encodeURIComponent(this.id);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var id = this.get(this.idAttribute);
+      return base.replace(/[^\/]$/, '$&/') + encodeURIComponent(id);
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // **parse** converts a response into the hash of attributes to be `set` on
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -557,7 +714,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Check if the model is currently in a valid state.
</span><span class="cx" style="display: block; padding: 0 10px">     isValid: function(options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return this._validate({}, _.extend(options || {}, { validate: true }));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return this._validate({}, _.defaults({validate: true}, options));
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Run validation against the next complete set of model attributes,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -573,23 +730,19 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Underscore methods that we want to implement on the Model.
-  var modelMethods = ['keys', 'values', 'pairs', 'invert', 'pick', 'omit'];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Underscore methods that we want to implement on the Model, mapped to the
+  // number of arguments they take.
+  var modelMethods = { keys: 1, values: 1, pairs: 1, invert: 1, pick: 0,
+      omit: 0, chain: 1, isEmpty: 1 };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Mix in each Underscore method as a proxy to `Model#attributes`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.each(modelMethods, function(method) {
-    Model.prototype[method] = function() {
-      var args = slice.call(arguments);
-      args.unshift(this.attributes);
-      return _[method].apply(_, args);
-    };
-  });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  addUnderscoreMethods(Model, modelMethods, 'attributes');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Backbone.Collection
</span><span class="cx" style="display: block; padding: 0 10px">   // -------------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // If models tend to represent a single row of data, a Backbone Collection is
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // more analagous to a table full of data ... or a small slice or page of that
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // more analogous to a table full of data ... or a small slice or page of that
</ins><span class="cx" style="display: block; padding: 0 10px">   // table, or a collection of rows that belong together for a particular reason
</span><span class="cx" style="display: block; padding: 0 10px">   // -- all of the messages in this particular folder, all of the documents
</span><span class="cx" style="display: block; padding: 0 10px">   // belonging to this particular author, and so on. Collections maintain
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -611,6 +764,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">   var setOptions = {add: true, remove: true, merge: true};
</span><span class="cx" style="display: block; padding: 0 10px">   var addOptions = {add: true, remove: false};
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Splices `insert` into `array` at index `at`.
+  var splice = function(array, insert, at) {
+    at = Math.min(Math.max(at, 0), array.length);
+    var tail = Array(array.length - at);
+    var length = insert.length;
+    for (var i = 0; i < tail.length; i++) tail[i] = array[i + at];
+    for (i = 0; i < length; i++) array[i + at] = insert[i];
+    for (i = 0; i < tail.length; i++) array[i + length + at] = tail[i];
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Define the Collection's inheritable methods.
</span><span class="cx" style="display: block; padding: 0 10px">   _.extend(Collection.prototype, Events, {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -625,7 +788,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // The JSON representation of a Collection is an array of the
</span><span class="cx" style="display: block; padding: 0 10px">     // models' attributes.
</span><span class="cx" style="display: block; padding: 0 10px">     toJSON: function(options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return this.map(function(model){ return model.toJSON(options); });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return this.map(function(model) { return model.toJSON(options); });
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Proxy `Backbone.sync` by default.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -633,32 +796,21 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return Backbone.sync.apply(this, arguments);
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Add a model, or list of models to the set.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Add a model, or list of models to the set. `models` may be Backbone
+    // Models or raw JavaScript objects to be converted to Models, or any
+    // combination of the two.
</ins><span class="cx" style="display: block; padding: 0 10px">     add: function(models, options) {
</span><span class="cx" style="display: block; padding: 0 10px">       return this.set(models, _.extend({merge: false}, options, addOptions));
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Remove a model, or a list of models from the set.
</span><span class="cx" style="display: block; padding: 0 10px">     remove: function(models, options) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      options = _.extend({}, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       var singular = !_.isArray(models);
</span><span class="cx" style="display: block; padding: 0 10px">       models = singular ? [models] : _.clone(models);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      options || (options = {});
-      var i, l, index, model;
-      for (i = 0, l = models.length; i < l; i++) {
-        model = models[i] = this.get(models[i]);
-        if (!model) continue;
-        delete this._byId[model.id];
-        delete this._byId[model.cid];
-        index = this.indexOf(model);
-        this.models.splice(index, 1);
-        this.length--;
-        if (!options.silent) {
-          options.index = index;
-          model.trigger('remove', model, this, options);
-        }
-        this._removeReference(model, options);
-      }
-      return singular ? models[0] : models;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var removed = this._removeModels(models, options);
+      if (!options.silent && removed) this.trigger('update', this, options);
+      return singular ? removed[0] : removed;
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Update a collection by `set`-ing a new list of models, adding new ones,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -666,78 +818,88 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // already exist in the collection, as necessary. Similar to **Model#set**,
</span><span class="cx" style="display: block; padding: 0 10px">     // the core operation for updating the data contained by the collection.
</span><span class="cx" style="display: block; padding: 0 10px">     set: function(models, options) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (models == null) return;
+
</ins><span class="cx" style="display: block; padding: 0 10px">       options = _.defaults({}, options, setOptions);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (options.parse) models = this.parse(models, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (options.parse && !this._isModel(models)) models = this.parse(models, options);
+
</ins><span class="cx" style="display: block; padding: 0 10px">       var singular = !_.isArray(models);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      models = singular ? (models ? [models] : []) : _.clone(models);
-      var i, l, id, model, attrs, existing, sort;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      models = singular ? [models] : models.slice();
+
</ins><span class="cx" style="display: block; padding: 0 10px">       var at = options.at;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var targetModel = this.model;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (at != null) at = +at;
+      if (at < 0) at += this.length + 1;
+
+      var set = [];
+      var toAdd = [];
+      var toRemove = [];
+      var modelMap = {};
+
+      var add = options.add;
+      var merge = options.merge;
+      var remove = options.remove;
+
+      var sort = false;
</ins><span class="cx" style="display: block; padding: 0 10px">       var sortable = this.comparator && (at == null) && options.sort !== false;
</span><span class="cx" style="display: block; padding: 0 10px">       var sortAttr = _.isString(this.comparator) ? this.comparator : null;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var toAdd = [], toRemove = [], modelMap = {};
-      var add = options.add, merge = options.merge, remove = options.remove;
-      var order = !sortable && add && remove ? [] : false;
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Turn bare objects into model references, and prevent invalid models
</span><span class="cx" style="display: block; padding: 0 10px">       // from being added.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (i = 0, l = models.length; i < l; i++) {
-        attrs = models[i] || {};
-        if (attrs instanceof Model) {
-          id = model = attrs;
-        } else {
-          id = attrs[targetModel.prototype.idAttribute || 'id'];
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var model;
+      for (var i = 0; i < models.length; i++) {
+        model = models[i];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // If a duplicate is found, prevent it from being added and
</span><span class="cx" style="display: block; padding: 0 10px">         // optionally merge it into the existing model.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (existing = this.get(id)) {
-          if (remove) modelMap[existing.cid] = true;
-          if (merge) {
-            attrs = attrs === model ? model.attributes : attrs;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        var existing = this.get(model);
+        if (existing) {
+          if (merge && model !== existing) {
+            var attrs = this._isModel(model) ? model.attributes : model;
</ins><span class="cx" style="display: block; padding: 0 10px">             if (options.parse) attrs = existing.parse(attrs, options);
</span><span class="cx" style="display: block; padding: 0 10px">             existing.set(attrs, options);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-            if (sortable && !sort && existing.hasChanged(sortAttr)) sort = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+            if (sortable && !sort) sort = existing.hasChanged(sortAttr);
</ins><span class="cx" style="display: block; padding: 0 10px">           }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!modelMap[existing.cid]) {
+            modelMap[existing.cid] = true;
+            set.push(existing);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">           models[i] = existing;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // If this is a new, valid model, push it to the `toAdd` list.
</span><span class="cx" style="display: block; padding: 0 10px">         } else if (add) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          model = models[i] = this._prepareModel(attrs, options);
-          if (!model) continue;
-          toAdd.push(model);
-          this._addReference(model, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          model = models[i] = this._prepareModel(model, options);
+          if (model) {
+            toAdd.push(model);
+            this._addReference(model, options);
+            modelMap[model.cid] = true;
+            set.push(model);
+          }
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
-        // Do not add multiple models with the same `id`.
-        model = existing || model;
-        if (order && (model.isNew() || !modelMap[model.id])) order.push(model);
-        modelMap[model.id] = true;
</del><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Remove nonexistent models if appropriate.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Remove stale models.
</ins><span class="cx" style="display: block; padding: 0 10px">       if (remove) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        for (i = 0, l = this.length; i < l; ++i) {
-          if (!modelMap[(model = this.models[i]).cid]) toRemove.push(model);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (i = 0; i < this.length; i++) {
+          model = this.models[i];
+          if (!modelMap[model.cid]) toRemove.push(model);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (toRemove.length) this.remove(toRemove, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (toRemove.length) this._removeModels(toRemove, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // See if sorting is needed, update `length` and splice in new models.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (toAdd.length || (order && order.length)) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var orderChanged = false;
+      var replace = !sortable && add && remove;
+      if (set.length && replace) {
+        orderChanged = this.length != set.length || _.some(this.models, function(model, index) {
+          return model !== set[index];
+        });
+        this.models.length = 0;
+        splice(this.models, set, 0);
+        this.length = this.models.length;
+      } else if (toAdd.length) {
</ins><span class="cx" style="display: block; padding: 0 10px">         if (sortable) sort = true;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        this.length += toAdd.length;
-        if (at != null) {
-          for (i = 0, l = toAdd.length; i < l; i++) {
-            this.models.splice(at + i, 0, toAdd[i]);
-          }
-        } else {
-          if (order) this.models.length = 0;
-          var orderedModels = order || toAdd;
-          for (i = 0, l = orderedModels.length; i < l; i++) {
-            this.models.push(orderedModels[i]);
-          }
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        splice(this.models, toAdd, at == null ? this.length : at);
+        this.length = this.models.length;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Silently sort the collection if appropriate.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -745,10 +907,13 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Unless silenced, it's time to fire all appropriate add/sort events.
</span><span class="cx" style="display: block; padding: 0 10px">       if (!options.silent) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        for (i = 0, l = toAdd.length; i < l; i++) {
-          (model = toAdd[i]).trigger('add', model, this, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        for (i = 0; i < toAdd.length; i++) {
+          if (at != null) options.index = at + i;
+          model = toAdd[i];
+          model.trigger('add', model, this, options);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (sort || (order && order.length)) this.trigger('sort', this, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (sort || orderChanged) this.trigger('sort', this, options);
+        if (toAdd.length || toRemove.length) this.trigger('update', this, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Return the added (or merged) model (or models).
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -760,8 +925,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // any granular `add` or `remove` events. Fires `reset` when finished.
</span><span class="cx" style="display: block; padding: 0 10px">     // Useful for bulk operations and optimizations.
</span><span class="cx" style="display: block; padding: 0 10px">     reset: function(models, options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      options || (options = {});
-      for (var i = 0, l = this.models.length; i < l; i++) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      options = options ? _.clone(options) : {};
+      for (var i = 0; i < this.models.length; i++) {
</ins><span class="cx" style="display: block; padding: 0 10px">         this._removeReference(this.models[i], options);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">       options.previousModels = this.models;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -779,8 +944,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // Remove a model from the end of the collection.
</span><span class="cx" style="display: block; padding: 0 10px">     pop: function(options) {
</span><span class="cx" style="display: block; padding: 0 10px">       var model = this.at(this.length - 1);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.remove(model, options);
-      return model;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return this.remove(model, options);
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Add a model to the beginning of the collection.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -791,8 +955,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // Remove a model from the beginning of the collection.
</span><span class="cx" style="display: block; padding: 0 10px">     shift: function(options) {
</span><span class="cx" style="display: block; padding: 0 10px">       var model = this.at(0);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.remove(model, options);
-      return model;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return this.remove(model, options);
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Slice out a sub-array of models from the collection.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -803,24 +966,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // Get a model from the set by id.
</span><span class="cx" style="display: block; padding: 0 10px">     get: function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">       if (obj == null) return void 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return this._byId[obj] || this._byId[obj.id] || this._byId[obj.cid];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var id = this.modelId(this._isModel(obj) ? obj.attributes : obj);
+      return this._byId[obj] || this._byId[id] || this._byId[obj.cid];
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Get the model at the given index.
</span><span class="cx" style="display: block; padding: 0 10px">     at: function(index) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (index < 0) index += this.length;
</ins><span class="cx" style="display: block; padding: 0 10px">       return this.models[index];
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Return models with matching attributes. Useful for simple cases of
</span><span class="cx" style="display: block; padding: 0 10px">     // `filter`.
</span><span class="cx" style="display: block; padding: 0 10px">     where: function(attrs, first) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (_.isEmpty(attrs)) return first ? void 0 : [];
-      return this[first ? 'find' : 'filter'](function(model) {
-        for (var key in attrs) {
-          if (attrs[key] !== model.get(key)) return false;
-        }
-        return true;
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return this[first ? 'find' : 'filter'](attrs);
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Return the first model with matching attributes. Useful for simple cases
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -833,16 +992,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // normal circumstances, as the set will maintain sort order as each item
</span><span class="cx" style="display: block; padding: 0 10px">     // is added.
</span><span class="cx" style="display: block; padding: 0 10px">     sort: function(options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var comparator = this.comparator;
+      if (!comparator) throw new Error('Cannot sort a set without a comparator');
</ins><span class="cx" style="display: block; padding: 0 10px">       options || (options = {});
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var length = comparator.length;
+      if (_.isFunction(comparator)) comparator = _.bind(comparator, this);
+
</ins><span class="cx" style="display: block; padding: 0 10px">       // Run sort based on type of `comparator`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (_.isString(this.comparator) || this.comparator.length === 1) {
-        this.models = this.sortBy(this.comparator, this);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (length === 1 || _.isString(comparator)) {
+        this.models = this.sortBy(comparator);
</ins><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        this.models.sort(_.bind(this.comparator, this));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        this.models.sort(comparator);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">       if (!options.silent) this.trigger('sort', this, options);
</span><span class="cx" style="display: block; padding: 0 10px">       return this;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -856,14 +1018,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // collection when they arrive. If `reset: true` is passed, the response
</span><span class="cx" style="display: block; padding: 0 10px">     // data will be passed through the `reset` method instead of `set`.
</span><span class="cx" style="display: block; padding: 0 10px">     fetch: function(options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      options = options ? _.clone(options) : {};
-      if (options.parse === void 0) options.parse = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      options = _.extend({parse: true}, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       var success = options.success;
</span><span class="cx" style="display: block; padding: 0 10px">       var collection = this;
</span><span class="cx" style="display: block; padding: 0 10px">       options.success = function(resp) {
</span><span class="cx" style="display: block; padding: 0 10px">         var method = options.reset ? 'reset' : 'set';
</span><span class="cx" style="display: block; padding: 0 10px">         collection[method](resp, options);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (success) success(collection, resp, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (success) success.call(options.context, collection, resp, options);
</ins><span class="cx" style="display: block; padding: 0 10px">         collection.trigger('sync', collection, resp, options);
</span><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px">       wrapError(this, options);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -875,13 +1036,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // wait for the server to agree.
</span><span class="cx" style="display: block; padding: 0 10px">     create: function(model, options) {
</span><span class="cx" style="display: block; padding: 0 10px">       options = options ? _.clone(options) : {};
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!(model = this._prepareModel(model, options))) return false;
-      if (!options.wait) this.add(model, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var wait = options.wait;
+      model = this._prepareModel(model, options);
+      if (!model) return false;
+      if (!wait) this.add(model, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       var collection = this;
</span><span class="cx" style="display: block; padding: 0 10px">       var success = options.success;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      options.success = function(model, resp) {
-        if (options.wait) collection.add(model, options);
-        if (success) success(model, resp, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      options.success = function(model, resp, callbackOpts) {
+        if (wait) collection.add(model, callbackOpts);
+        if (success) success.call(callbackOpts.context, model, resp, callbackOpts);
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px">       model.save(null, options);
</span><span class="cx" style="display: block; padding: 0 10px">       return model;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -895,9 +1058,17 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Create a new collection with an identical list of models as this one.
</span><span class="cx" style="display: block; padding: 0 10px">     clone: function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return new this.constructor(this.models);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return new this.constructor(this.models, {
+        model: this.model,
+        comparator: this.comparator
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Define how to uniquely identify models in the collection.
+    modelId: function (attrs) {
+      return attrs[this.model.prototype.idAttribute || 'id'];
+    },
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Private method to reset all internal state. Called when the collection
</span><span class="cx" style="display: block; padding: 0 10px">     // is first initialized or reset.
</span><span class="cx" style="display: block; padding: 0 10px">     _reset: function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -909,7 +1080,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // Prepare a hash of attributes (or other model) to be added to this
</span><span class="cx" style="display: block; padding: 0 10px">     // collection.
</span><span class="cx" style="display: block; padding: 0 10px">     _prepareModel: function(attrs, options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (attrs instanceof Model) return attrs;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (this._isModel(attrs)) {
+        if (!attrs.collection) attrs.collection = this;
+        return attrs;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">       options = options ? _.clone(options) : {};
</span><span class="cx" style="display: block; padding: 0 10px">       options.collection = this;
</span><span class="cx" style="display: block; padding: 0 10px">       var model = new this.model(attrs, options);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -918,16 +1092,47 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return false;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Internal method called by both remove and set.
+    _removeModels: function(models, options) {
+      var removed = [];
+      for (var i = 0; i < models.length; i++) {
+        var model = this.get(models[i]);
+        if (!model) continue;
+
+        var index = this.indexOf(model);
+        this.models.splice(index, 1);
+        this.length--;
+
+        if (!options.silent) {
+          options.index = index;
+          model.trigger('remove', model, this, options);
+        }
+
+        removed.push(model);
+        this._removeReference(model, options);
+      }
+      return removed.length ? removed : false;
+    },
+
+    // Method for checking whether an object should be considered a model for
+    // the purposes of adding to the collection.
+    _isModel: function (model) {
+      return model instanceof Model;
+    },
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Internal method to create a model's ties to a collection.
</span><span class="cx" style="display: block; padding: 0 10px">     _addReference: function(model, options) {
</span><span class="cx" style="display: block; padding: 0 10px">       this._byId[model.cid] = model;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (model.id != null) this._byId[model.id] = model;
-      if (!model.collection) model.collection = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var id = this.modelId(model.attributes);
+      if (id != null) this._byId[id] = model;
</ins><span class="cx" style="display: block; padding: 0 10px">       model.on('all', this._onModelEvent, this);
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Internal method to sever a model's ties to a collection.
</span><span class="cx" style="display: block; padding: 0 10px">     _removeReference: function(model, options) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      delete this._byId[model.cid];
+      var id = this.modelId(model.attributes);
+      if (id != null) delete this._byId[id];
</ins><span class="cx" style="display: block; padding: 0 10px">       if (this === model.collection) delete model.collection;
</span><span class="cx" style="display: block; padding: 0 10px">       model.off('all', this._onModelEvent, this);
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -939,9 +1144,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">     _onModelEvent: function(event, model, collection, options) {
</span><span class="cx" style="display: block; padding: 0 10px">       if ((event === 'add' || event === 'remove') && collection !== this) return;
</span><span class="cx" style="display: block; padding: 0 10px">       if (event === 'destroy') this.remove(model, options);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (model && event === 'change:' + model.idAttribute) {
-        delete this._byId[model.previous(model.idAttribute)];
-        if (model.id != null) this._byId[model.id] = model;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (event === 'change') {
+        var prevId = this.modelId(model.previousAttributes());
+        var id = this.modelId(model.attributes);
+        if (prevId !== id) {
+          if (prevId != null) delete this._byId[prevId];
+          if (id != null) this._byId[id] = model;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">       this.trigger.apply(this, arguments);
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -951,35 +1160,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Underscore methods that we want to implement on the Collection.
</span><span class="cx" style="display: block; padding: 0 10px">   // 90% of the core usefulness of Backbone Collections is actually implemented
</span><span class="cx" style="display: block; padding: 0 10px">   // right here:
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var methods = ['forEach', 'each', 'map', 'collect', 'reduce', 'foldl',
-    'inject', 'reduceRight', 'foldr', 'find', 'detect', 'filter', 'select',
-    'reject', 'every', 'all', 'some', 'any', 'include', 'contains', 'invoke',
-    'max', 'min', 'toArray', 'size', 'first', 'head', 'take', 'initial', 'rest',
-    'tail', 'drop', 'last', 'without', 'difference', 'indexOf', 'shuffle',
-    'lastIndexOf', 'isEmpty', 'chain', 'sample'];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var collectionMethods = { 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};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Mix in each Underscore method as a proxy to `Collection#models`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.each(methods, function(method) {
-    Collection.prototype[method] = function() {
-      var args = slice.call(arguments);
-      args.unshift(this.models);
-      return _[method].apply(_, args);
-    };
-  });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  addUnderscoreMethods(Collection, collectionMethods, 'models');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Underscore methods that take a property name as an argument.
-  var attributeMethods = ['groupBy', 'countBy', 'sortBy', 'indexBy'];
-
-  // Use attributes instead of properties.
-  _.each(attributeMethods, function(method) {
-    Collection.prototype[method] = function(value, context) {
-      var iterator = _.isFunction(value) ? value : function(model) {
-        return model.get(value);
-      };
-      return _[method](this.models, iterator, context);
-    };
-  });
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Backbone.View
</span><span class="cx" style="display: block; padding: 0 10px">   // -------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -995,17 +1187,15 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // if an existing element is not provided...
</span><span class="cx" style="display: block; padding: 0 10px">   var View = Backbone.View = function(options) {
</span><span class="cx" style="display: block; padding: 0 10px">     this.cid = _.uniqueId('view');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    options || (options = {});
</del><span class="cx" style="display: block; padding: 0 10px">     _.extend(this, _.pick(options, viewOptions));
</span><span class="cx" style="display: block; padding: 0 10px">     this._ensureElement();
</span><span class="cx" style="display: block; padding: 0 10px">     this.initialize.apply(this, arguments);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    this.delegateEvents();
</del><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Cached regex to split keys for `delegate`.
</span><span class="cx" style="display: block; padding: 0 10px">   var delegateEventSplitter = /^(\S+)\s*(.*)$/;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // List of view options to be merged as properties.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // List of view options to be set as properties.
</ins><span class="cx" style="display: block; padding: 0 10px">   var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName', 'events'];
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Set up all inheritable **Backbone.View** properties and methods.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1034,21 +1224,37 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // Remove this view by taking the element out of the DOM, and removing any
</span><span class="cx" style="display: block; padding: 0 10px">     // applicable Backbone.Events listeners.
</span><span class="cx" style="display: block; padding: 0 10px">     remove: function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.$el.remove();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      this._removeElement();
</ins><span class="cx" style="display: block; padding: 0 10px">       this.stopListening();
</span><span class="cx" style="display: block; padding: 0 10px">       return this;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Change the view's element (`this.el` property), including event
-    // re-delegation.
-    setElement: function(element, delegate) {
-      if (this.$el) this.undelegateEvents();
-      this.$el = element instanceof Backbone.$ ? element : Backbone.$(element);
-      this.el = this.$el[0];
-      if (delegate !== false) this.delegateEvents();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Remove this view's element from the document and all event listeners
+    // attached to it. Exposed for subclasses using an alternative DOM
+    // manipulation API.
+    _removeElement: function() {
+      this.$el.remove();
+    },
+
+    // Change the view's element (`this.el` property) and re-delegate the
+    // view's events on the new element.
+    setElement: function(element) {
+      this.undelegateEvents();
+      this._setElement(element);
+      this.delegateEvents();
</ins><span class="cx" style="display: block; padding: 0 10px">       return this;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Creates the `this.el` and `this.$el` references for this view using the
+    // given `el`. `el` can be a CSS selector or an HTML string, a jQuery
+    // context or an element. Subclasses can override this to utilize an
+    // alternative DOM manipulation API and are only required to set the
+    // `this.el` property.
+    _setElement: function(el) {
+      this.$el = el instanceof Backbone.$ ? el : Backbone.$(el);
+      this.el = this.$el[0];
+    },
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Set callbacks, where `this.events` is a hash of
</span><span class="cx" style="display: block; padding: 0 10px">     //
</span><span class="cx" style="display: block; padding: 0 10px">     // *{"event selector": "callback"}*
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1062,37 +1268,49 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // pairs. Callbacks will be bound to the view, with `this` set properly.
</span><span class="cx" style="display: block; padding: 0 10px">     // Uses event delegation for efficiency.
</span><span class="cx" style="display: block; padding: 0 10px">     // Omitting the selector binds the event to `this.el`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // This only works for delegate-able events: not `focus`, `blur`, and
-    // not `change`, `submit`, and `reset` in Internet Explorer.
</del><span class="cx" style="display: block; padding: 0 10px">     delegateEvents: function(events) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!(events || (events = _.result(this, 'events')))) return this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      events || (events = _.result(this, 'events'));
+      if (!events) return this;
</ins><span class="cx" style="display: block; padding: 0 10px">       this.undelegateEvents();
</span><span class="cx" style="display: block; padding: 0 10px">       for (var key in events) {
</span><span class="cx" style="display: block; padding: 0 10px">         var method = events[key];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (!_.isFunction(method)) method = this[events[key]];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!_.isFunction(method)) method = this[method];
</ins><span class="cx" style="display: block; padding: 0 10px">         if (!method) continue;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-
</del><span class="cx" style="display: block; padding: 0 10px">         var match = key.match(delegateEventSplitter);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var eventName = match[1], selector = match[2];
-        method = _.bind(method, this);
-        eventName += '.delegateEvents' + this.cid;
-        if (selector === '') {
-          this.$el.on(eventName, method);
-        } else {
-          this.$el.on(eventName, selector, method);
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        this.delegate(match[1], match[2], _.bind(method, this));
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">       return this;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Clears all callbacks previously bound to the view with `delegateEvents`.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Add a single event listener to the view's element (or a child element
+    // using `selector`). This only works for delegate-able events: not `focus`,
+    // `blur`, and not `change`, `submit`, and `reset` in Internet Explorer.
+    delegate: function(eventName, selector, listener) {
+      this.$el.on(eventName + '.delegateEvents' + this.cid, selector, listener);
+      return this;
+    },
+
+    // Clears all callbacks previously bound to the view by `delegateEvents`.
</ins><span class="cx" style="display: block; padding: 0 10px">     // You usually don't need to use this, but may wish to if you have multiple
</span><span class="cx" style="display: block; padding: 0 10px">     // Backbone views attached to the same DOM element.
</span><span class="cx" style="display: block; padding: 0 10px">     undelegateEvents: function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this.$el.off('.delegateEvents' + this.cid);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (this.$el) this.$el.off('.delegateEvents' + this.cid);
</ins><span class="cx" style="display: block; padding: 0 10px">       return this;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // A finer-grained `undelegateEvents` for removing a single delegated event.
+    // `selector` and `listener` are both optional.
+    undelegate: function(eventName, selector, listener) {
+      this.$el.off(eventName + '.delegateEvents' + this.cid, selector, listener);
+      return this;
+    },
+
+    // Produces a DOM element to be assigned to your view. Exposed for
+    // subclasses using an alternative DOM manipulation API.
+    _createElement: function(tagName) {
+      return document.createElement(tagName);
+    },
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Ensure that the View has a DOM element to render into.
</span><span class="cx" style="display: block; padding: 0 10px">     // If `this.el` is a string, pass it through `$()`, take the first
</span><span class="cx" style="display: block; padding: 0 10px">     // matching element, and re-assign it to `el`. Otherwise, create
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1102,11 +1320,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">         var attrs = _.extend({}, _.result(this, 'attributes'));
</span><span class="cx" style="display: block; padding: 0 10px">         if (this.id) attrs.id = _.result(this, 'id');
</span><span class="cx" style="display: block; padding: 0 10px">         if (this.className) attrs['class'] = _.result(this, 'className');
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        var $el = Backbone.$('<' + _.result(this, 'tagName') + '>').attr(attrs);
-        this.setElement($el, false);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        this.setElement(this._createElement(_.result(this, 'tagName')));
+        this._setAttributes(attrs);
</ins><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        this.setElement(_.result(this, 'el'), false);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        this.setElement(_.result(this, 'el'));
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    },
+
+    // Set attributes from a hash on this view's element.  Exposed for
+    // subclasses using an alternative DOM manipulation API.
+    _setAttributes: function(attributes) {
+      this.$el.attr(attributes);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1175,14 +1399,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">       params.processData = false;
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // If we're sending a `PATCH` request, and we're in an old Internet Explorer
-    // that still has ActiveX enabled by default, override jQuery to use that
-    // for XHR instead. Remove this line when jQuery supports `PATCH` on IE8.
-    if (params.type === 'PATCH' && noXhrPatch) {
-      params.xhr = function() {
-        return new ActiveXObject("Microsoft.XMLHTTP");
-      };
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Pass along `textStatus` and `errorThrown` from jQuery.
+    var error = options.error;
+    options.error = function(xhr, textStatus, errorThrown) {
+      options.textStatus = textStatus;
+      options.errorThrown = errorThrown;
+      if (error) error.call(options.context, xhr, textStatus, errorThrown);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Make the request, allowing the user to override any Ajax options.
</span><span class="cx" style="display: block; padding: 0 10px">     var xhr = options.xhr = Backbone.ajax(_.extend(params, options));
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1190,10 +1413,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">     return xhr;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var noXhrPatch =
-    typeof window !== 'undefined' && !!window.ActiveXObject &&
-      !(window.XMLHttpRequest && (new XMLHttpRequest).dispatchEvent);
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
</span><span class="cx" style="display: block; padding: 0 10px">   var methodMap = {
</span><span class="cx" style="display: block; padding: 0 10px">     'create': 'POST',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1251,17 +1470,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">       var router = this;
</span><span class="cx" style="display: block; padding: 0 10px">       Backbone.history.route(route, function(fragment) {
</span><span class="cx" style="display: block; padding: 0 10px">         var args = router._extractParameters(route, fragment);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        router.execute(callback, args);
-        router.trigger.apply(router, ['route:' + name].concat(args));
-        router.trigger('route', name, args);
-        Backbone.history.trigger('route', router, name, args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (router.execute(callback, args, name) !== false) {
+          router.trigger.apply(router, ['route:' + name].concat(args));
+          router.trigger('route', name, args);
+          Backbone.history.trigger('route', router, name, args);
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">       return this;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Execute a route handler with the provided parameters.  This is an
</span><span class="cx" style="display: block; padding: 0 10px">     // excellent place to do pre-route setup or post-route cleanup.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    execute: function(callback, args) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    execute: function(callback, args, name) {
</ins><span class="cx" style="display: block; padding: 0 10px">       if (callback) callback.apply(this, args);
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1319,7 +1539,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // falls back to polling.
</span><span class="cx" style="display: block; padding: 0 10px">   var History = Backbone.History = function() {
</span><span class="cx" style="display: block; padding: 0 10px">     this.handlers = [];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    _.bindAll(this, 'checkUrl');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    this.checkUrl = _.bind(this.checkUrl, this);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Ensure that `History` can be used outside of the browser.
</span><span class="cx" style="display: block; padding: 0 10px">     if (typeof window !== 'undefined') {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1334,12 +1554,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Cached regex for stripping leading and trailing slashes.
</span><span class="cx" style="display: block; padding: 0 10px">   var rootStripper = /^\/+|\/+$/g;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Cached regex for detecting MSIE.
-  var isExplorer = /msie [\w.]+/;
-
-  // Cached regex for removing a trailing slash.
-  var trailingSlash = /\/$/;
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Cached regex for stripping urls of hash.
</span><span class="cx" style="display: block; padding: 0 10px">   var pathStripper = /#.*$/;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1355,9 +1569,31 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Are we at the app root?
</span><span class="cx" style="display: block; padding: 0 10px">     atRoot: function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return this.location.pathname.replace(/[^\/]$/, '$&/') === this.root;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var path = this.location.pathname.replace(/[^\/]$/, '$&/');
+      return path === this.root && !this.getSearch();
</ins><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Does the pathname match the root?
+    matchRoot: function() {
+      var path = this.decodeFragment(this.location.pathname);
+      var root = path.slice(0, this.root.length - 1) + '/';
+      return root === this.root;
+    },
+
+    // Unicode characters in `location.pathname` are percent encoded so they're
+    // decoded for comparison. `%25` should not be decoded since it may be part
+    // of an encoded parameter.
+    decodeFragment: function(fragment) {
+      return decodeURI(fragment.replace(/%25/g, '%2525'));
+    },
+
+    // In IE6, the hash fragment and search params are incorrect if the
+    // fragment contains `?`.
+    getSearch: function() {
+      var match = this.location.href.replace(/#.*/, '').match(/\?.+/);
+      return match ? match[0] : '';
+    },
+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Gets the true hash value. Cannot use location.hash directly due to bug
</span><span class="cx" style="display: block; padding: 0 10px">     // in Firefox where location.hash will always be decoded.
</span><span class="cx" style="display: block; padding: 0 10px">     getHash: function(window) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1365,14 +1601,19 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return match ? match[1] : '';
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Get the cross-browser normalized URL fragment, either from the URL,
-    // the hash, or the override.
-    getFragment: function(fragment, forcePushState) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Get the pathname and search params, without the root.
+    getPath: function() {
+      var path = this.decodeFragment(
+        this.location.pathname + this.getSearch()
+      ).slice(this.root.length - 1);
+      return path.charAt(0) === '/' ? path.slice(1) : path;
+    },
+
+    // Get the cross-browser normalized URL fragment from the path or hash.
+    getFragment: function(fragment) {
</ins><span class="cx" style="display: block; padding: 0 10px">       if (fragment == null) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (this._hasPushState || !this._wantsHashChange || forcePushState) {
-          fragment = decodeURI(this.location.pathname + this.location.search);
-          var root = this.root.replace(trailingSlash, '');
-          if (!fragment.indexOf(root)) fragment = fragment.slice(root.length);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (this._usePushState || !this._wantsHashChange) {
+          fragment = this.getPath();
</ins><span class="cx" style="display: block; padding: 0 10px">         } else {
</span><span class="cx" style="display: block; padding: 0 10px">           fragment = this.getHash();
</span><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1383,7 +1624,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // Start the hash change handling, returning `true` if the current URL matches
</span><span class="cx" style="display: block; padding: 0 10px">     // an existing route, and `false` otherwise.
</span><span class="cx" style="display: block; padding: 0 10px">     start: function(options) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (History.started) throw new Error("Backbone.history has already been started");
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (History.started) throw new Error('Backbone.history has already been started');
</ins><span class="cx" style="display: block; padding: 0 10px">       History.started = true;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Figure out the initial configuration. Do we need an iframe?
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1391,36 +1632,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">       this.options          = _.extend({root: '/'}, this.options, options);
</span><span class="cx" style="display: block; padding: 0 10px">       this.root             = this.options.root;
</span><span class="cx" style="display: block; padding: 0 10px">       this._wantsHashChange = this.options.hashChange !== false;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      this._hasHashChange   = 'onhashchange' in window && (document.documentMode === void 0 || document.documentMode > 7);
+      this._useHashChange   = this._wantsHashChange && this._hasHashChange;
</ins><span class="cx" style="display: block; padding: 0 10px">       this._wantsPushState  = !!this.options.pushState;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      this._hasPushState    = !!(this.options.pushState && this.history && this.history.pushState);
-      var fragment          = this.getFragment();
-      var docMode           = document.documentMode;
-      var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      this._hasPushState    = !!(this.history && this.history.pushState);
+      this._usePushState    = this._wantsPushState && this._hasPushState;
+      this.fragment         = this.getFragment();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // Normalize root to always include a leading and trailing slash.
</span><span class="cx" style="display: block; padding: 0 10px">       this.root = ('/' + this.root + '/').replace(rootStripper, '/');
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (oldIE && this._wantsHashChange) {
-        var frame = Backbone.$('<iframe src="javascript:0" tabindex="-1">');
-        this.iframe = frame.hide().appendTo('body')[0].contentWindow;
-        this.navigate(fragment);
-      }
-
-      // Depending on whether we're using pushState or hashes, and whether
-      // 'onhashchange' is supported, determine how we check the URL state.
-      if (this._hasPushState) {
-        Backbone.$(window).on('popstate', this.checkUrl);
-      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
-        Backbone.$(window).on('hashchange', this.checkUrl);
-      } else if (this._wantsHashChange) {
-        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
-      }
-
-      // Determine if we need to change the base url, for a pushState link
-      // opened by a non-pushState browser.
-      this.fragment = fragment;
-      var loc = this.location;
-
</del><span class="cx" style="display: block; padding: 0 10px">       // Transition from hashChange to pushState or vice versa if both are
</span><span class="cx" style="display: block; padding: 0 10px">       // requested.
</span><span class="cx" style="display: block; padding: 0 10px">       if (this._wantsHashChange && this._wantsPushState) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1428,27 +1649,75 @@
</span><span class="cx" style="display: block; padding: 0 10px">         // If we've started off with a route from a `pushState`-enabled
</span><span class="cx" style="display: block; padding: 0 10px">         // browser, but we're currently in a browser that doesn't support it...
</span><span class="cx" style="display: block; padding: 0 10px">         if (!this._hasPushState && !this.atRoot()) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          this.fragment = this.getFragment(null, true);
-          this.location.replace(this.root + '#' + this.fragment);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          var root = this.root.slice(0, -1) || '/';
+          this.location.replace(root + '#' + this.getPath());
</ins><span class="cx" style="display: block; padding: 0 10px">           // Return immediately as browser will do redirect to new url
</span><span class="cx" style="display: block; padding: 0 10px">           return true;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">         // Or if we've started out with a hash-based route, but we're currently
</span><span class="cx" style="display: block; padding: 0 10px">         // in a browser where it could be `pushState`-based instead...
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        } else if (this._hasPushState && this.atRoot() && loc.hash) {
-          this.fragment = this.getHash().replace(routeStripper, '');
-          this.history.replaceState({}, document.title, this.root + this.fragment);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        } else if (this._hasPushState && this.atRoot()) {
+          this.navigate(this.getHash(), {replace: true});
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Proxy an iframe to handle location events if the browser doesn't
+      // support the `hashchange` event, HTML5 history, or the user wants
+      // `hashChange` but not `pushState`.
+      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 body = document.body;
+        // Using `appendChild` will throw on IE < 9 if the document is not ready.
+        var iWindow = body.insertBefore(this.iframe, body.firstChild).contentWindow;
+        iWindow.document.open();
+        iWindow.document.close();
+        iWindow.location.hash = '#' + this.fragment;
+      }
+
+      // Add a cross-platform `addEventListener` shim for older browsers.
+      var addEventListener = window.addEventListener || function (eventName, listener) {
+        return attachEvent('on' + eventName, listener);
+      };
+
+      // Depending on whether we're using pushState or hashes, and whether
+      // 'onhashchange' is supported, determine how we check the URL state.
+      if (this._usePushState) {
+        addEventListener('popstate', this.checkUrl, false);
+      } else if (this._useHashChange && !this.iframe) {
+        addEventListener('hashchange', this.checkUrl, false);
+      } else if (this._wantsHashChange) {
+        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
+      }
+
</ins><span class="cx" style="display: block; padding: 0 10px">       if (!this.options.silent) return this.loadUrl();
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
</span><span class="cx" style="display: block; padding: 0 10px">     // but possibly useful for unit testing Routers.
</span><span class="cx" style="display: block; padding: 0 10px">     stop: function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      Backbone.$(window).off('popstate', this.checkUrl).off('hashchange', this.checkUrl);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Add a cross-platform `removeEventListener` shim for older browsers.
+      var removeEventListener = window.removeEventListener || function (eventName, listener) {
+        return detachEvent('on' + eventName, listener);
+      };
+
+      // Remove window listeners.
+      if (this._usePushState) {
+        removeEventListener('popstate', this.checkUrl, false);
+      } else if (this._useHashChange && !this.iframe) {
+        removeEventListener('hashchange', this.checkUrl, false);
+      }
+
+      // Clean up the iframe if necessary.
+      if (this.iframe) {
+        document.body.removeChild(this.iframe);
+        this.iframe = null;
+      }
+
+      // Some environments will throw when clearing an undefined interval.
</ins><span class="cx" style="display: block; padding: 0 10px">       if (this._checkUrlInterval) clearInterval(this._checkUrlInterval);
</span><span class="cx" style="display: block; padding: 0 10px">       History.started = false;
</span><span class="cx" style="display: block; padding: 0 10px">     },
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1463,9 +1732,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // calls `loadUrl`, normalizing across the hidden iframe.
</span><span class="cx" style="display: block; padding: 0 10px">     checkUrl: function(e) {
</span><span class="cx" style="display: block; padding: 0 10px">       var current = this.getFragment();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      // If the user pressed the back button, the iframe's hash will have
+      // changed and we should use that for comparison.
</ins><span class="cx" style="display: block; padding: 0 10px">       if (current === this.fragment && this.iframe) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        current = this.getFragment(this.getHash(this.iframe));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        current = this.getHash(this.iframe.contentWindow);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">       if (current === this.fragment) return false;
</span><span class="cx" style="display: block; padding: 0 10px">       if (this.iframe) this.navigate(current);
</span><span class="cx" style="display: block; padding: 0 10px">       this.loadUrl();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1475,8 +1748,10 @@
</span><span class="cx" style="display: block; padding: 0 10px">     // match, returns `true`. If no defined routes matches the fragment,
</span><span class="cx" style="display: block; padding: 0 10px">     // returns `false`.
</span><span class="cx" style="display: block; padding: 0 10px">     loadUrl: function(fragment) {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // If the root doesn't match, no routes can match either.
+      if (!this.matchRoot()) return false;
</ins><span class="cx" style="display: block; padding: 0 10px">       fragment = this.fragment = this.getFragment(fragment);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return _.any(this.handlers, function(handler) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return _.some(this.handlers, function(handler) {
</ins><span class="cx" style="display: block; padding: 0 10px">         if (handler.route.test(fragment)) {
</span><span class="cx" style="display: block; padding: 0 10px">           handler.callback(fragment);
</span><span class="cx" style="display: block; padding: 0 10px">           return true;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1495,31 +1770,42 @@
</span><span class="cx" style="display: block; padding: 0 10px">       if (!History.started) return false;
</span><span class="cx" style="display: block; padding: 0 10px">       if (!options || options === true) options = {trigger: !!options};
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var url = this.root + (fragment = this.getFragment(fragment || ''));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Normalize the fragment.
+      fragment = this.getFragment(fragment || '');
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Strip the hash for matching.
-      fragment = fragment.replace(pathStripper, '');
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Don't include a trailing slash on the root.
+      var root = this.root;
+      if (fragment === '' || fragment.charAt(0) === '?') {
+        root = root.slice(0, -1) || '/';
+      }
+      var url = root + fragment;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Strip the hash and decode for matching.
+      fragment = this.decodeFragment(fragment.replace(pathStripper, ''));
+
</ins><span class="cx" style="display: block; padding: 0 10px">       if (this.fragment === fragment) return;
</span><span class="cx" style="display: block; padding: 0 10px">       this.fragment = fragment;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Don't include a trailing slash on the root.
-      if (fragment === '' && url !== '/') url = url.slice(0, -1);
-
</del><span class="cx" style="display: block; padding: 0 10px">       // If pushState is available, we use it to set the fragment as a real URL.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (this._hasPushState) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (this._usePushState) {
</ins><span class="cx" style="display: block; padding: 0 10px">         this.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, url);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // If hash changes haven't been explicitly disabled, update the hash
</span><span class="cx" style="display: block; padding: 0 10px">       // fragment to store history.
</span><span class="cx" style="display: block; padding: 0 10px">       } else if (this._wantsHashChange) {
</span><span class="cx" style="display: block; padding: 0 10px">         this._updateHash(this.location, fragment, options.replace);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        if (this.iframe && (fragment !== this.getFragment(this.getHash(this.iframe)))) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (this.iframe && (fragment !== this.getHash(this.iframe.contentWindow))) {
+          var iWindow = this.iframe.contentWindow;
+
</ins><span class="cx" style="display: block; padding: 0 10px">           // Opening and closing the iframe tricks IE7 and earlier to push a
</span><span class="cx" style="display: block; padding: 0 10px">           // history entry on hash-tag change.  When replace is true, we don't
</span><span class="cx" style="display: block; padding: 0 10px">           // want this.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          if(!options.replace) this.iframe.document.open().close();
-          this._updateHash(this.iframe.location, fragment, options.replace);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!options.replace) {
+            iWindow.document.open();
+            iWindow.document.close();
+          }
+
+          this._updateHash(iWindow.location, fragment, options.replace);
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       // If you've told us that you explicitly don't want fallback hashchange-
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1550,7 +1836,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Helpers
</span><span class="cx" style="display: block; padding: 0 10px">   // -------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Helper function to correctly set up the prototype chain, for subclasses.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Helper function to correctly set up the prototype chain for subclasses.
</ins><span class="cx" style="display: block; padding: 0 10px">   // Similar to `goog.inherits`, but uses a hash of prototype properties and
</span><span class="cx" style="display: block; padding: 0 10px">   // class properties to be extended.
</span><span class="cx" style="display: block; padding: 0 10px">   var extend = function(protoProps, staticProps) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1559,7 +1845,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // The constructor function for the new subclass is either defined by you
</span><span class="cx" style="display: block; padding: 0 10px">     // (the "constructor" property in your `extend` definition), or defaulted
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // by us to simply call the parent's constructor.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // by us to simply call the parent constructor.
</ins><span class="cx" style="display: block; padding: 0 10px">     if (protoProps && _.has(protoProps, 'constructor')) {
</span><span class="cx" style="display: block; padding: 0 10px">       child = protoProps.constructor;
</span><span class="cx" style="display: block; padding: 0 10px">     } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1570,7 +1856,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">     _.extend(child, parent, staticProps);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Set the prototype chain to inherit from `parent`, without calling
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // `parent`'s constructor function.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // `parent` constructor function.
</ins><span class="cx" style="display: block; padding: 0 10px">     var Surrogate = function(){ this.constructor = child; };
</span><span class="cx" style="display: block; padding: 0 10px">     Surrogate.prototype = parent.prototype;
</span><span class="cx" style="display: block; padding: 0 10px">     child.prototype = new Surrogate;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1598,7 +1884,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   var wrapError = function(model, options) {
</span><span class="cx" style="display: block; padding: 0 10px">     var error = options.error;
</span><span class="cx" style="display: block; padding: 0 10px">     options.error = function(resp) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (error) error(model, resp, options);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (error) error.call(options.context, model, resp, options);
</ins><span class="cx" style="display: block; padding: 0 10px">       model.trigger('error', model, resp, options);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span></span></pre></div>
<a id="trunksrcwpincludesjsbackboneminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/backbone.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/backbone.min.js  2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/js/backbone.min.js    2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1 +1 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-(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))dele
 te 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.attri
 butes;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.se
 t(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){ret
 urn 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.a
 ttributes: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({silen
 t: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.model
 s.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&
 quot;,"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",&quo
 t;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,fu
 nction(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;th
 is.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=t
 his.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=functio
 n(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});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+(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){r
 eturn 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&quot
 ;,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],th
 is,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=funct
 ion(){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&&
 amp;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&amp
 ;&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,r
 educeRight: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:funct
 ion(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.t
 ype!=="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("ro
 ute",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 Erro
 r("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(),{repla
 ce: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;t
 his.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;v
 ar 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});
</ins></span></pre></div>
<a id="trunksrcwpincludesjsmediaviewsmediadetailsjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/media/views/media-details.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/media/views/media-details.js     2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/js/media/views/media-details.js       2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -23,14 +23,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                this.on( 'media:setting:remove', wp.media.mixin.unsetPlayers, this );
</span><span class="cx" style="display: block; padding: 0 10px">                this.on( 'media:setting:remove', this.render );
</span><span class="cx" style="display: block; padding: 0 10px">                this.on( 'media:setting:remove', this.setPlayer );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                this.events = _.extend( this.events, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               AttachmentDisplay.prototype.initialize.apply( this, arguments );
+       },
+
+       events: function(){
+               return _.extend( {
</ins><span class="cx" style="display: block; padding: 0 10px">                         'click .remove-setting' : 'removeSetting',
</span><span class="cx" style="display: block; padding: 0 10px">                        'change .content-track' : 'setTracks',
</span><span class="cx" style="display: block; padding: 0 10px">                        'click .remove-track' : 'setTracks',
</span><span class="cx" style="display: block; padding: 0 10px">                        'click .add-media-source' : 'addSource'
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                } );
-
-               AttachmentDisplay.prototype.initialize.apply( this, arguments );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         }, AttachmentDisplay.prototype.events );
</ins><span class="cx" style="display: block; padding: 0 10px">         },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        prepare: function() {
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediaaudiovideojs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/media-audiovideo.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/media-audiovideo.js      2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/js/media-audiovideo.js        2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -728,14 +728,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                this.on( 'media:setting:remove', wp.media.mixin.unsetPlayers, this );
</span><span class="cx" style="display: block; padding: 0 10px">                this.on( 'media:setting:remove', this.render );
</span><span class="cx" style="display: block; padding: 0 10px">                this.on( 'media:setting:remove', this.setPlayer );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                this.events = _.extend( this.events, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+               AttachmentDisplay.prototype.initialize.apply( this, arguments );
+       },
+
+       events: function(){
+               return _.extend( {
</ins><span class="cx" style="display: block; padding: 0 10px">                         'click .remove-setting' : 'removeSetting',
</span><span class="cx" style="display: block; padding: 0 10px">                        'change .content-track' : 'setTracks',
</span><span class="cx" style="display: block; padding: 0 10px">                        'click .remove-track' : 'setTracks',
</span><span class="cx" style="display: block; padding: 0 10px">                        'click .add-media-source' : 'addSource'
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                } );
-
-               AttachmentDisplay.prototype.initialize.apply( this, arguments );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         }, AttachmentDisplay.prototype.events );
</ins><span class="cx" style="display: block; padding: 0 10px">         },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        prepare: function() {
</span></span></pre></div>
<a id="trunksrcwpincludesjsunderscorejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/underscore.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/underscore.js    2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/js/underscore.js      2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,6 +1,6 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//     Underscore.js 1.6.0
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+//     Underscore.js 1.8.3
</ins><span class="cx" style="display: block; padding: 0 10px"> //     http://underscorejs.org
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
</ins><span class="cx" style="display: block; padding: 0 10px"> //     Underscore may be freely distributed under the MIT license.
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> (function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -14,9 +14,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Save the previous value of the `_` variable.
</span><span class="cx" style="display: block; padding: 0 10px">   var previousUnderscore = root._;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Establish the object that gets returned to break out of a loop iteration.
-  var breaker = {};
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Save bytes in the minified (but not gzipped) version:
</span><span class="cx" style="display: block; padding: 0 10px">   var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -24,26 +21,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">   var
</span><span class="cx" style="display: block; padding: 0 10px">     push             = ArrayProto.push,
</span><span class="cx" style="display: block; padding: 0 10px">     slice            = ArrayProto.slice,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    concat           = ArrayProto.concat,
</del><span class="cx" style="display: block; padding: 0 10px">     toString         = ObjProto.toString,
</span><span class="cx" style="display: block; padding: 0 10px">     hasOwnProperty   = ObjProto.hasOwnProperty;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // All **ECMAScript 5** native function implementations that we hope to use
</span><span class="cx" style="display: block; padding: 0 10px">   // are declared here.
</span><span class="cx" style="display: block; padding: 0 10px">   var
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    nativeForEach      = ArrayProto.forEach,
-    nativeMap          = ArrayProto.map,
-    nativeReduce       = ArrayProto.reduce,
-    nativeReduceRight  = ArrayProto.reduceRight,
-    nativeFilter       = ArrayProto.filter,
-    nativeEvery        = ArrayProto.every,
-    nativeSome         = ArrayProto.some,
-    nativeIndexOf      = ArrayProto.indexOf,
-    nativeLastIndexOf  = ArrayProto.lastIndexOf,
</del><span class="cx" style="display: block; padding: 0 10px">     nativeIsArray      = Array.isArray,
</span><span class="cx" style="display: block; padding: 0 10px">     nativeKeys         = Object.keys,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    nativeBind         = FuncProto.bind;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    nativeBind         = FuncProto.bind,
+    nativeCreate       = Object.create;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Naked function reference for surrogate-prototype-swapping.
+  var Ctor = function(){};
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Create a safe reference to the Underscore object for use below.
</span><span class="cx" style="display: block; padding: 0 10px">   var _ = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (obj instanceof _) return obj;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -53,8 +44,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Export the Underscore object for **Node.js**, with
</span><span class="cx" style="display: block; padding: 0 10px">   // backwards-compatibility for the old `require()` API. If we're in
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // the browser, add `_` as a global object via a string identifier,
-  // for Closure Compiler "advanced" mode.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // the browser, add `_` as a global object.
</ins><span class="cx" style="display: block; padding: 0 10px">   if (typeof exports !== 'undefined') {
</span><span class="cx" style="display: block; padding: 0 10px">     if (typeof module !== 'undefined' && module.exports) {
</span><span class="cx" style="display: block; padding: 0 10px">       exports = module.exports = _;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -65,161 +55,217 @@
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Current version.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.VERSION = '1.6.0';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.VERSION = '1.8.3';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Internal function that returns an efficient (for current engines) version
+  // of the passed-in callback, to be repeatedly applied in other Underscore
+  // functions.
+  var optimizeCb = function(func, context, argCount) {
+    if (context === void 0) return func;
+    switch (argCount == null ? 3 : argCount) {
+      case 1: return function(value) {
+        return func.call(context, value);
+      };
+      case 2: return function(value, other) {
+        return func.call(context, value, other);
+      };
+      case 3: return function(value, index, collection) {
+        return func.call(context, value, index, collection);
+      };
+      case 4: return function(accumulator, value, index, collection) {
+        return func.call(context, accumulator, value, index, collection);
+      };
+    }
+    return function() {
+      return func.apply(context, arguments);
+    };
+  };
+
+  // A mostly-internal function to generate callbacks that can be applied
+  // to each element in a collection, returning the desired result â€” either
+  // identity, an arbitrary callback, a property matcher, or a property accessor.
+  var cb = function(value, context, argCount) {
+    if (value == null) return _.identity;
+    if (_.isFunction(value)) return optimizeCb(value, context, argCount);
+    if (_.isObject(value)) return _.matcher(value);
+    return _.property(value);
+  };
+  _.iteratee = function(value, context) {
+    return cb(value, context, Infinity);
+  };
+
+  // An internal function for creating assigner functions.
+  var createAssigner = function(keysFunc, undefinedOnly) {
+    return function(obj) {
+      var length = arguments.length;
+      if (length < 2 || obj == null) return obj;
+      for (var index = 1; index < length; index++) {
+        var source = arguments[index],
+            keys = keysFunc(source),
+            l = keys.length;
+        for (var i = 0; i < l; i++) {
+          var key = keys[i];
+          if (!undefinedOnly || obj[key] === void 0) obj[key] = source[key];
+        }
+      }
+      return obj;
+    };
+  };
+
+  // An internal function for creating a new object that inherits from another.
+  var baseCreate = function(prototype) {
+    if (!_.isObject(prototype)) return {};
+    if (nativeCreate) return nativeCreate(prototype);
+    Ctor.prototype = prototype;
+    var result = new Ctor;
+    Ctor.prototype = null;
+    return result;
+  };
+
+  var property = function(key) {
+    return function(obj) {
+      return obj == null ? void 0 : obj[key];
+    };
+  };
+
+  // Helper for collection methods to determine whether a collection
+  // should be iterated as an array or as an object
+  // Related: http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
+  // Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
+  var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
+  var getLength = property('length');
+  var isArrayLike = function(collection) {
+    var length = getLength(collection);
+    return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Collection Functions
</span><span class="cx" style="display: block; padding: 0 10px">   // --------------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // The cornerstone, an `each` implementation, aka `forEach`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Handles objects with the built-in `forEach`, arrays, and raw objects.
-  // Delegates to **ECMAScript 5**'s native `forEach` if available.
-  var each = _.each = _.forEach = function(obj, iterator, context) {
-    if (obj == null) return obj;
-    if (nativeForEach && obj.forEach === nativeForEach) {
-      obj.forEach(iterator, context);
-    } else if (obj.length === +obj.length) {
-      for (var i = 0, length = obj.length; i < length; i++) {
-        if (iterator.call(context, obj[i], i, obj) === breaker) return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Handles raw objects in addition to array-likes. Treats all
+  // sparse array-likes as if they were dense.
+  _.each = _.forEach = function(obj, iteratee, context) {
+    iteratee = optimizeCb(iteratee, context);
+    var i, length;
+    if (isArrayLike(obj)) {
+      for (i = 0, length = obj.length; i < length; i++) {
+        iteratee(obj[i], i, obj);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     } else {
</span><span class="cx" style="display: block; padding: 0 10px">       var keys = _.keys(obj);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (var i = 0, length = keys.length; i < length; i++) {
-        if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      for (i = 0, length = keys.length; i < length; i++) {
+        iteratee(obj[keys[i]], keys[i], obj);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px">     return obj;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Return the results of applying the iterator to each element.
-  // Delegates to **ECMAScript 5**'s native `map` if available.
-  _.map = _.collect = function(obj, iterator, context) {
-    var results = [];
-    if (obj == null) return results;
-    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
-    each(obj, function(value, index, list) {
-      results.push(iterator.call(context, value, index, list));
-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Return the results of applying the iteratee to each element.
+  _.map = _.collect = function(obj, iteratee, context) {
+    iteratee = cb(iteratee, context);
+    var keys = !isArrayLike(obj) && _.keys(obj),
+        length = (keys || obj).length,
+        results = Array(length);
+    for (var index = 0; index < length; index++) {
+      var currentKey = keys ? keys[index] : index;
+      results[index] = iteratee(obj[currentKey], currentKey, obj);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px">     return results;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var reduceError = 'Reduce of empty array with no initial value';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Create a reducing function iterating left or right.
+  function createReduce(dir) {
+    // Optimized iterator function as using arguments.length
+    // in the main function will deoptimize the, see #1991.
+    function iterator(obj, iteratee, memo, keys, index, length) {
+      for (; index >= 0 && index < length; index += dir) {
+        var currentKey = keys ? keys[index] : index;
+        memo = iteratee(memo, obj[currentKey], currentKey, obj);
+      }
+      return memo;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // **Reduce** builds up a single result from a list of values, aka `inject`,
-  // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
-  _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) {
-    var initial = arguments.length > 2;
-    if (obj == null) obj = [];
-    if (nativeReduce && obj.reduce === nativeReduce) {
-      if (context) iterator = _.bind(iterator, context);
-      return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);
-    }
-    each(obj, function(value, index, list) {
-      if (!initial) {
-        memo = value;
-        initial = true;
-      } else {
-        memo = iterator.call(context, memo, value, index, list);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return function(obj, iteratee, memo, context) {
+      iteratee = optimizeCb(iteratee, context, 4);
+      var keys = !isArrayLike(obj) && _.keys(obj),
+          length = (keys || obj).length,
+          index = dir > 0 ? 0 : length - 1;
+      // Determine the initial value if none is provided.
+      if (arguments.length < 3) {
+        memo = obj[keys ? keys[index] : index];
+        index += dir;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    });
-    if (!initial) throw new TypeError(reduceError);
-    return memo;
-  };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return iterator(obj, iteratee, memo, keys, index, length);
+    };
+  }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // **Reduce** builds up a single result from a list of values, aka `inject`,
+  // or `foldl`.
+  _.reduce = _.foldl = _.inject = createReduce(1);
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // The right-associative version of reduce, also known as `foldr`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
-  _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
-    var initial = arguments.length > 2;
-    if (obj == null) obj = [];
-    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
-      if (context) iterator = _.bind(iterator, context);
-      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
-    }
-    var length = obj.length;
-    if (length !== +length) {
-      var keys = _.keys(obj);
-      length = keys.length;
-    }
-    each(obj, function(value, index, list) {
-      index = keys ? keys[--length] : --length;
-      if (!initial) {
-        memo = obj[index];
-        initial = true;
-      } else {
-        memo = iterator.call(context, memo, obj[index], index, list);
-      }
-    });
-    if (!initial) throw new TypeError(reduceError);
-    return memo;
-  };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.reduceRight = _.foldr = createReduce(-1);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return the first value which passes a truth test. Aliased as `detect`.
</span><span class="cx" style="display: block; padding: 0 10px">   _.find = _.detect = function(obj, predicate, context) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var result;
-    any(obj, function(value, index, list) {
-      if (predicate.call(context, value, index, list)) {
-        result = value;
-        return true;
-      }
-    });
-    return result;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var key;
+    if (isArrayLike(obj)) {
+      key = _.findIndex(obj, predicate, context);
+    } else {
+      key = _.findKey(obj, predicate, context);
+    }
+    if (key !== void 0 && key !== -1) return obj[key];
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return all the elements that pass a truth test.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Delegates to **ECMAScript 5**'s native `filter` if available.
</del><span class="cx" style="display: block; padding: 0 10px">   // Aliased as `select`.
</span><span class="cx" style="display: block; padding: 0 10px">   _.filter = _.select = function(obj, predicate, context) {
</span><span class="cx" style="display: block; padding: 0 10px">     var results = [];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (obj == null) return results;
-    if (nativeFilter && obj.filter === nativeFilter) return obj.filter(predicate, context);
-    each(obj, function(value, index, list) {
-      if (predicate.call(context, value, index, list)) results.push(value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    predicate = cb(predicate, context);
+    _.each(obj, function(value, index, list) {
+      if (predicate(value, index, list)) results.push(value);
</ins><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px">     return results;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return all the elements for which a truth test fails.
</span><span class="cx" style="display: block; padding: 0 10px">   _.reject = function(obj, predicate, context) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return _.filter(obj, function(value, index, list) {
-      return !predicate.call(context, value, index, list);
-    }, context);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.filter(obj, _.negate(cb(predicate)), context);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Determine whether all of the elements match a truth test.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Delegates to **ECMAScript 5**'s native `every` if available.
</del><span class="cx" style="display: block; padding: 0 10px">   // Aliased as `all`.
</span><span class="cx" style="display: block; padding: 0 10px">   _.every = _.all = function(obj, predicate, context) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    predicate || (predicate = _.identity);
-    var result = true;
-    if (obj == null) return result;
-    if (nativeEvery && obj.every === nativeEvery) return obj.every(predicate, context);
-    each(obj, function(value, index, list) {
-      if (!(result = result && predicate.call(context, value, index, list))) return breaker;
-    });
-    return !!result;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    predicate = cb(predicate, context);
+    var keys = !isArrayLike(obj) && _.keys(obj),
+        length = (keys || obj).length;
+    for (var index = 0; index < length; index++) {
+      var currentKey = keys ? keys[index] : index;
+      if (!predicate(obj[currentKey], currentKey, obj)) return false;
+    }
+    return true;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Determine if at least one element in the object matches a truth test.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Delegates to **ECMAScript 5**'s native `some` if available.
</del><span class="cx" style="display: block; padding: 0 10px">   // Aliased as `any`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var any = _.some = _.any = function(obj, predicate, context) {
-    predicate || (predicate = _.identity);
-    var result = false;
-    if (obj == null) return result;
-    if (nativeSome && obj.some === nativeSome) return obj.some(predicate, context);
-    each(obj, function(value, index, list) {
-      if (result || (result = predicate.call(context, value, index, list))) return breaker;
-    });
-    return !!result;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.some = _.any = function(obj, predicate, context) {
+    predicate = cb(predicate, context);
+    var keys = !isArrayLike(obj) && _.keys(obj),
+        length = (keys || obj).length;
+    for (var index = 0; index < length; index++) {
+      var currentKey = keys ? keys[index] : index;
+      if (predicate(obj[currentKey], currentKey, obj)) return true;
+    }
+    return false;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Determine if the array or object contains a given value (using `===`).
-  // Aliased as `include`.
-  _.contains = _.include = function(obj, target) {
-    if (obj == null) return false;
-    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
-    return any(obj, function(value) {
-      return value === target;
-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Determine if the array or object contains a given item (using `===`).
+  // Aliased as `includes` and `include`.
+  _.contains = _.includes = _.include = function(obj, item, fromIndex, guard) {
+    if (!isArrayLike(obj)) obj = _.values(obj);
+    if (typeof fromIndex != 'number' || guard) fromIndex = 0;
+    return _.indexOf(obj, item, fromIndex) >= 0;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Invoke a method (with arguments) on every item in a collection.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -227,7 +273,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">     var args = slice.call(arguments, 2);
</span><span class="cx" style="display: block; padding: 0 10px">     var isFunc = _.isFunction(method);
</span><span class="cx" style="display: block; padding: 0 10px">     return _.map(obj, function(value) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return (isFunc ? method : value[method]).apply(value, args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var func = isFunc ? method : value[method];
+      return func == null ? func : func.apply(value, args);
</ins><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -239,60 +286,76 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Convenience version of a common use case of `filter`: selecting only objects
</span><span class="cx" style="display: block; padding: 0 10px">   // containing specific `key:value` pairs.
</span><span class="cx" style="display: block; padding: 0 10px">   _.where = function(obj, attrs) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return _.filter(obj, _.matches(attrs));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.filter(obj, _.matcher(attrs));
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Convenience version of a common use case of `find`: getting the first object
</span><span class="cx" style="display: block; padding: 0 10px">   // containing specific `key:value` pairs.
</span><span class="cx" style="display: block; padding: 0 10px">   _.findWhere = function(obj, attrs) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return _.find(obj, _.matches(attrs));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.find(obj, _.matcher(attrs));
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Return the maximum element or (element-based computation).
-  // Can't optimize arrays of integers longer than 65,535 elements.
-  // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)
-  _.max = function(obj, iterator, context) {
-    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
-      return Math.max.apply(Math, obj);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Return the maximum element (or element-based computation).
+  _.max = function(obj, iteratee, context) {
+    var result = -Infinity, lastComputed = -Infinity,
+        value, computed;
+    if (iteratee == null && obj != null) {
+      obj = isArrayLike(obj) ? obj : _.values(obj);
+      for (var i = 0, length = obj.length; i < length; i++) {
+        value = obj[i];
+        if (value > result) {
+          result = value;
+        }
+      }
+    } else {
+      iteratee = cb(iteratee, context);
+      _.each(obj, function(value, index, list) {
+        computed = iteratee(value, index, list);
+        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
+          result = value;
+          lastComputed = computed;
+        }
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var result = -Infinity, lastComputed = -Infinity;
-    each(obj, function(value, index, list) {
-      var computed = iterator ? iterator.call(context, value, index, list) : value;
-      if (computed > lastComputed) {
-        result = value;
-        lastComputed = computed;
-      }
-    });
</del><span class="cx" style="display: block; padding: 0 10px">     return result;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return the minimum element (or element-based computation).
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.min = function(obj, iterator, context) {
-    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
-      return Math.min.apply(Math, obj);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.min = function(obj, iteratee, context) {
+    var result = Infinity, lastComputed = Infinity,
+        value, computed;
+    if (iteratee == null && obj != null) {
+      obj = isArrayLike(obj) ? obj : _.values(obj);
+      for (var i = 0, length = obj.length; i < length; i++) {
+        value = obj[i];
+        if (value < result) {
+          result = value;
+        }
+      }
+    } else {
+      iteratee = cb(iteratee, context);
+      _.each(obj, function(value, index, list) {
+        computed = iteratee(value, index, list);
+        if (computed < lastComputed || computed === Infinity && result === Infinity) {
+          result = value;
+          lastComputed = computed;
+        }
+      });
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var result = Infinity, lastComputed = Infinity;
-    each(obj, function(value, index, list) {
-      var computed = iterator ? iterator.call(context, value, index, list) : value;
-      if (computed < lastComputed) {
-        result = value;
-        lastComputed = computed;
-      }
-    });
</del><span class="cx" style="display: block; padding: 0 10px">     return result;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Shuffle an array, using the modern version of the
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Shuffle a collection, using the modern version of the
</ins><span class="cx" style="display: block; padding: 0 10px">   // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).
</span><span class="cx" style="display: block; padding: 0 10px">   _.shuffle = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var rand;
-    var index = 0;
-    var shuffled = [];
-    each(obj, function(value) {
-      rand = _.random(index++);
-      shuffled[index - 1] = shuffled[rand];
-      shuffled[rand] = value;
-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var set = isArrayLike(obj) ? obj : _.values(obj);
+    var length = set.length;
+    var shuffled = Array(length);
+    for (var index = 0, rand; index < length; index++) {
+      rand = _.random(0, index);
+      if (rand !== index) shuffled[index] = shuffled[rand];
+      shuffled[rand] = set[index];
+    }
</ins><span class="cx" style="display: block; padding: 0 10px">     return shuffled;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -301,27 +364,20 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // The internal `guard` argument allows it to work with `map`.
</span><span class="cx" style="display: block; padding: 0 10px">   _.sample = function(obj, n, guard) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (n == null || guard) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (obj.length !== +obj.length) obj = _.values(obj);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!isArrayLike(obj)) obj = _.values(obj);
</ins><span class="cx" style="display: block; padding: 0 10px">       return obj[_.random(obj.length - 1)];
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px">     return _.shuffle(obj).slice(0, Math.max(0, n));
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // An internal function to generate lookup iterators.
-  var lookupIterator = function(value) {
-    if (value == null) return _.identity;
-    if (_.isFunction(value)) return value;
-    return _.property(value);
-  };
-
-  // Sort the object's values by a criterion produced by an iterator.
-  _.sortBy = function(obj, iterator, context) {
-    iterator = lookupIterator(iterator);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Sort the object's values by a criterion produced by an iteratee.
+  _.sortBy = function(obj, iteratee, context) {
+    iteratee = cb(iteratee, context);
</ins><span class="cx" style="display: block; padding: 0 10px">     return _.pluck(_.map(obj, function(value, index, list) {
</span><span class="cx" style="display: block; padding: 0 10px">       return {
</span><span class="cx" style="display: block; padding: 0 10px">         value: value,
</span><span class="cx" style="display: block; padding: 0 10px">         index: index,
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        criteria: iterator.call(context, value, index, list)
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        criteria: iteratee(value, index, list)
</ins><span class="cx" style="display: block; padding: 0 10px">       };
</span><span class="cx" style="display: block; padding: 0 10px">     }).sort(function(left, right) {
</span><span class="cx" style="display: block; padding: 0 10px">       var a = left.criteria;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -336,12 +392,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // An internal function used for aggregate "group by" operations.
</span><span class="cx" style="display: block; padding: 0 10px">   var group = function(behavior) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return function(obj, iterator, context) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return function(obj, iteratee, context) {
</ins><span class="cx" style="display: block; padding: 0 10px">       var result = {};
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      iterator = lookupIterator(iterator);
-      each(obj, function(value, index) {
-        var key = iterator.call(context, value, index, obj);
-        behavior(result, key, value);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      iteratee = cb(iteratee, context);
+      _.each(obj, function(value, index) {
+        var key = iteratee(value, index, obj);
+        behavior(result, value, key);
</ins><span class="cx" style="display: block; padding: 0 10px">       });
</span><span class="cx" style="display: block; padding: 0 10px">       return result;
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -349,50 +405,48 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Groups the object's values by a criterion. Pass either a string attribute
</span><span class="cx" style="display: block; padding: 0 10px">   // to group by, or a function that returns the criterion.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.groupBy = group(function(result, key, value) {
-    _.has(result, key) ? result[key].push(value) : result[key] = [value];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.groupBy = group(function(result, value, key) {
+    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
</ins><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Indexes the object's values by a criterion, similar to `groupBy`, but for
</span><span class="cx" style="display: block; padding: 0 10px">   // when you know that your index values will be unique.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.indexBy = group(function(result, key, value) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.indexBy = group(function(result, value, key) {
</ins><span class="cx" style="display: block; padding: 0 10px">     result[key] = value;
</span><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Counts instances of an object that group by a certain criterion. Pass
</span><span class="cx" style="display: block; padding: 0 10px">   // either a string attribute to count by, or a function that returns the
</span><span class="cx" style="display: block; padding: 0 10px">   // criterion.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.countBy = group(function(result, key) {
-    _.has(result, key) ? result[key]++ : result[key] = 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.countBy = group(function(result, value, key) {
+    if (_.has(result, key)) result[key]++; else result[key] = 1;
</ins><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Use a comparator function to figure out the smallest index at which
-  // an object should be inserted so as to maintain order. Uses binary search.
-  _.sortedIndex = function(array, obj, iterator, context) {
-    iterator = lookupIterator(iterator);
-    var value = iterator.call(context, obj);
-    var low = 0, high = array.length;
-    while (low < high) {
-      var mid = (low + high) >>> 1;
-      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
-    }
-    return low;
-  };
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Safely create a real, live array from anything iterable.
</span><span class="cx" style="display: block; padding: 0 10px">   _.toArray = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (!obj) return [];
</span><span class="cx" style="display: block; padding: 0 10px">     if (_.isArray(obj)) return slice.call(obj);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (obj.length === +obj.length) return _.map(obj, _.identity);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (isArrayLike(obj)) return _.map(obj, _.identity);
</ins><span class="cx" style="display: block; padding: 0 10px">     return _.values(obj);
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return the number of elements in an object.
</span><span class="cx" style="display: block; padding: 0 10px">   _.size = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (obj == null) return 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return isArrayLike(obj) ? obj.length : _.keys(obj).length;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Split a collection into two arrays: one whose elements all satisfy the given
+  // predicate, and one whose elements all do not satisfy the predicate.
+  _.partition = function(obj, predicate, context) {
+    predicate = cb(predicate, context);
+    var pass = [], fail = [];
+    _.each(obj, function(value, key, obj) {
+      (predicate(value, key, obj) ? pass : fail).push(value);
+    });
+    return [pass, fail];
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Array Functions
</span><span class="cx" style="display: block; padding: 0 10px">   // ---------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -401,33 +455,30 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // allows it to work with `_.map`.
</span><span class="cx" style="display: block; padding: 0 10px">   _.first = _.head = _.take = function(array, n, guard) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (array == null) return void 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if ((n == null) || guard) return array[0];
-    if (n < 0) return [];
-    return slice.call(array, 0, n);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (n == null || guard) return array[0];
+    return _.initial(array, array.length - n);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Returns everything but the last entry of the array. Especially useful on
</span><span class="cx" style="display: block; padding: 0 10px">   // the arguments object. Passing **n** will return all the values in
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // the array, excluding the last N. The **guard** check allows it to work with
-  // `_.map`.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // the array, excluding the last N.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.initial = function(array, n, guard) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Get the last element of an array. Passing **n** will return the last N
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // values in the array. The **guard** check allows it to work with `_.map`.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // values in the array.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.last = function(array, n, guard) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (array == null) return void 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if ((n == null) || guard) return array[array.length - 1];
-    return slice.call(array, Math.max(array.length - n, 0));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (n == null || guard) return array[array.length - 1];
+    return _.rest(array, Math.max(0, array.length - n));
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.
</span><span class="cx" style="display: block; padding: 0 10px">   // Especially useful on the arguments object. Passing an **n** will return
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // the rest N values in the array. The **guard**
-  // check allows it to work with `_.map`.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // the rest N values in the array.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.rest = _.tail = _.drop = function(array, n, guard) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return slice.call(array, (n == null) || guard ? 1 : n);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return slice.call(array, n == null || guard ? 1 : n);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Trim out all falsy values from an array.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -436,23 +487,28 @@
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Internal implementation of a recursive `flatten` function.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var flatten = function(input, shallow, output) {
-    if (shallow && _.every(input, _.isArray)) {
-      return concat.apply(output, input);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var flatten = function(input, shallow, strict, startIndex) {
+    var output = [], idx = 0;
+    for (var i = startIndex || 0, length = getLength(input); i < length; i++) {
+      var value = input[i];
+      if (isArrayLike(value) && (_.isArray(value) || _.isArguments(value))) {
+        //flatten current level of array or arguments object
+        if (!shallow) value = flatten(value, shallow, strict);
+        var j = 0, len = value.length;
+        output.length += len;
+        while (j < len) {
+          output[idx++] = value[j++];
+        }
+      } else if (!strict) {
+        output[idx++] = value;
+      }
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    each(input, function(value) {
-      if (_.isArray(value) || _.isArguments(value)) {
-        shallow ? push.apply(output, value) : flatten(value, shallow, output);
-      } else {
-        output.push(value);
-      }
-    });
</del><span class="cx" style="display: block; padding: 0 10px">     return output;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Flatten out an array, either recursively (by default), or just one level.
</span><span class="cx" style="display: block; padding: 0 10px">   _.flatten = function(array, shallow) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return flatten(array, shallow, []);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return flatten(array, shallow, false);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return a version of the array that does not contain the specified value(s).
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -460,79 +516,91 @@
</span><span class="cx" style="display: block; padding: 0 10px">     return _.difference(array, slice.call(arguments, 1));
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Split an array into two arrays: one whose elements all satisfy the given
-  // predicate, and one whose elements all do not satisfy the predicate.
-  _.partition = function(array, predicate) {
-    var pass = [], fail = [];
-    each(array, function(elem) {
-      (predicate(elem) ? pass : fail).push(elem);
-    });
-    return [pass, fail];
-  };
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Produce a duplicate-free version of the array. If the array has already
</span><span class="cx" style="display: block; padding: 0 10px">   // been sorted, you have the option of using a faster algorithm.
</span><span class="cx" style="display: block; padding: 0 10px">   // Aliased as `unique`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.uniq = _.unique = function(array, isSorted, iterator, context) {
-    if (_.isFunction(isSorted)) {
-      context = iterator;
-      iterator = isSorted;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.uniq = _.unique = function(array, isSorted, iteratee, context) {
+    if (!_.isBoolean(isSorted)) {
+      context = iteratee;
+      iteratee = isSorted;
</ins><span class="cx" style="display: block; padding: 0 10px">       isSorted = false;
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var initial = iterator ? _.map(array, iterator, context) : array;
-    var results = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (iteratee != null) iteratee = cb(iteratee, context);
+    var result = [];
</ins><span class="cx" style="display: block; padding: 0 10px">     var seen = [];
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    each(initial, function(value, index) {
-      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
-        seen.push(value);
-        results.push(array[index]);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    for (var i = 0, length = getLength(array); i < length; i++) {
+      var value = array[i],
+          computed = iteratee ? iteratee(value, i, array) : value;
+      if (isSorted) {
+        if (!i || seen !== computed) result.push(value);
+        seen = computed;
+      } else if (iteratee) {
+        if (!_.contains(seen, computed)) {
+          seen.push(computed);
+          result.push(value);
+        }
+      } else if (!_.contains(result, value)) {
+        result.push(value);
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    });
-    return results;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    }
+    return result;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Produce an array that contains the union: each distinct element from all of
</span><span class="cx" style="display: block; padding: 0 10px">   // the passed-in arrays.
</span><span class="cx" style="display: block; padding: 0 10px">   _.union = function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return _.uniq(_.flatten(arguments, true));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.uniq(flatten(arguments, true, true));
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Produce an array that contains every item shared between all the
</span><span class="cx" style="display: block; padding: 0 10px">   // passed-in arrays.
</span><span class="cx" style="display: block; padding: 0 10px">   _.intersection = function(array) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var rest = slice.call(arguments, 1);
-    return _.filter(_.uniq(array), function(item) {
-      return _.every(rest, function(other) {
-        return _.contains(other, item);
-      });
-    });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var result = [];
+    var argsLength = arguments.length;
+    for (var i = 0, length = getLength(array); i < length; i++) {
+      var item = array[i];
+      if (_.contains(result, item)) continue;
+      for (var j = 1; j < argsLength; j++) {
+        if (!_.contains(arguments[j], item)) break;
+      }
+      if (j === argsLength) result.push(item);
+    }
+    return result;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Take the difference between one array and a number of other arrays.
</span><span class="cx" style="display: block; padding: 0 10px">   // Only the elements present in just the first array will remain.
</span><span class="cx" style="display: block; padding: 0 10px">   _.difference = function(array) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
-    return _.filter(array, function(value){ return !_.contains(rest, value); });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var rest = flatten(arguments, true, true, 1);
+    return _.filter(array, function(value){
+      return !_.contains(rest, value);
+    });
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Zip together multiple lists into a single array -- elements that share
</span><span class="cx" style="display: block; padding: 0 10px">   // an index go together.
</span><span class="cx" style="display: block; padding: 0 10px">   _.zip = function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var length = _.max(_.pluck(arguments, 'length').concat(0));
-    var results = new Array(length);
-    for (var i = 0; i < length; i++) {
-      results[i] = _.pluck(arguments, '' + i);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.unzip(arguments);
+  };
+
+  // Complement of _.zip. Unzip accepts an array of arrays and groups
+  // each array's elements on shared indices
+  _.unzip = function(array) {
+    var length = array && _.max(array, getLength).length || 0;
+    var result = Array(length);
+
+    for (var index = 0; index < length; index++) {
+      result[index] = _.pluck(array, index);
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return results;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return result;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Converts lists into objects. Pass either a single array of `[key, value]`
</span><span class="cx" style="display: block; padding: 0 10px">   // pairs, or two parallel arrays of the same length -- one of keys, and one of
</span><span class="cx" style="display: block; padding: 0 10px">   // the corresponding values.
</span><span class="cx" style="display: block; padding: 0 10px">   _.object = function(list, values) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (list == null) return {};
</del><span class="cx" style="display: block; padding: 0 10px">     var result = {};
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    for (var i = 0, length = list.length; i < length; i++) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    for (var i = 0, length = getLength(list); i < length; i++) {
</ins><span class="cx" style="display: block; padding: 0 10px">       if (values) {
</span><span class="cx" style="display: block; padding: 0 10px">         result[list[i]] = values[i];
</span><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -542,57 +610,83 @@
</span><span class="cx" style="display: block; padding: 0 10px">     return result;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),
-  // we need this function. Return the position of the first occurrence of an
-  // item in an array, or -1 if the item is not included in the array.
-  // Delegates to **ECMAScript 5**'s native `indexOf` if available.
-  // If the array is large and already in sort order, pass `true`
-  // for **isSorted** to use binary search.
-  _.indexOf = function(array, item, isSorted) {
-    if (array == null) return -1;
-    var i = 0, length = array.length;
-    if (isSorted) {
-      if (typeof isSorted == 'number') {
-        i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
-      } else {
-        i = _.sortedIndex(array, item);
-        return array[i] === item ? i : -1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Generator function to create the findIndex and findLastIndex functions
+  function createPredicateIndexFinder(dir) {
+    return function(array, predicate, context) {
+      predicate = cb(predicate, context);
+      var length = getLength(array);
+      var index = dir > 0 ? 0 : length - 1;
+      for (; index >= 0 && index < length; index += dir) {
+        if (predicate(array[index], index, array)) return index;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    }
-    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
-    for (; i < length; i++) if (array[i] === item) return i;
-    return -1;
-  };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return -1;
+    };
+  }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
-  _.lastIndexOf = function(array, item, from) {
-    if (array == null) return -1;
-    var hasIndex = from != null;
-    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
-      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns the first index on an array-like that passes a predicate test
+  _.findIndex = createPredicateIndexFinder(1);
+  _.findLastIndex = createPredicateIndexFinder(-1);
+
+  // Use a comparator function to figure out the smallest index at which
+  // an object should be inserted so as to maintain order. Uses binary search.
+  _.sortedIndex = function(array, obj, iteratee, context) {
+    iteratee = cb(iteratee, context, 1);
+    var value = iteratee(obj);
+    var low = 0, high = getLength(array);
+    while (low < high) {
+      var mid = Math.floor((low + high) / 2);
+      if (iteratee(array[mid]) < value) low = mid + 1; else high = mid;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var i = (hasIndex ? from : array.length);
-    while (i--) if (array[i] === item) return i;
-    return -1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return low;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Generator function to create the indexOf and lastIndexOf functions
+  function createIndexFinder(dir, predicateFind, sortedIndex) {
+    return function(array, item, idx) {
+      var i = 0, length = getLength(array);
+      if (typeof idx == 'number') {
+        if (dir > 0) {
+            i = idx >= 0 ? idx : Math.max(idx + length, i);
+        } else {
+            length = idx >= 0 ? Math.min(idx + 1, length) : idx + length + 1;
+        }
+      } else if (sortedIndex && idx && length) {
+        idx = sortedIndex(array, item);
+        return array[idx] === item ? idx : -1;
+      }
+      if (item !== item) {
+        idx = predicateFind(slice.call(array, i, length), _.isNaN);
+        return idx >= 0 ? idx + i : -1;
+      }
+      for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx += dir) {
+        if (array[idx] === item) return idx;
+      }
+      return -1;
+    };
+  }
+
+  // Return the position of the first occurrence of an item in an array,
+  // or -1 if the item is not included in the array.
+  // If the array is large and already in sort order, pass `true`
+  // for **isSorted** to use binary search.
+  _.indexOf = createIndexFinder(1, _.findIndex, _.sortedIndex);
+  _.lastIndexOf = createIndexFinder(-1, _.findLastIndex);
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Generate an integer Array containing an arithmetic progression. A port of
</span><span class="cx" style="display: block; padding: 0 10px">   // the native Python `range()` function. See
</span><span class="cx" style="display: block; padding: 0 10px">   // [the Python documentation](http://docs.python.org/library/functions.html#range).
</span><span class="cx" style="display: block; padding: 0 10px">   _.range = function(start, stop, step) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (arguments.length <= 1) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (stop == null) {
</ins><span class="cx" style="display: block; padding: 0 10px">       stop = start || 0;
</span><span class="cx" style="display: block; padding: 0 10px">       start = 0;
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    step = arguments[2] || 1;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    step = step || 1;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var length = Math.max(Math.ceil((stop - start) / step), 0);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var idx = 0;
-    var range = new Array(length);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var range = Array(length);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    while(idx < length) {
-      range[idx++] = start;
-      start += step;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    for (var idx = 0; idx < length; idx++, start += step) {
+      range[idx] = start;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return range;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -601,26 +695,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Function (ahem) Functions
</span><span class="cx" style="display: block; padding: 0 10px">   // ------------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Reusable constructor function for prototype setting.
-  var ctor = function(){};
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Determines whether to execute a function as a constructor
+  // or a normal function with the provided arguments
+  var executeBound = function(sourceFunc, boundFunc, context, callingContext, args) {
+    if (!(callingContext instanceof boundFunc)) return sourceFunc.apply(context, args);
+    var self = baseCreate(sourceFunc.prototype);
+    var result = sourceFunc.apply(self, args);
+    if (_.isObject(result)) return result;
+    return self;
+  };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Create a function bound to a given object (assigning `this`, and arguments,
</span><span class="cx" style="display: block; padding: 0 10px">   // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
</span><span class="cx" style="display: block; padding: 0 10px">   // available.
</span><span class="cx" style="display: block; padding: 0 10px">   _.bind = function(func, context) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var args, bound;
</del><span class="cx" style="display: block; padding: 0 10px">     if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (!_.isFunction(func)) throw new TypeError;
-    args = slice.call(arguments, 2);
-    return bound = function() {
-      if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));
-      ctor.prototype = func.prototype;
-      var self = new ctor;
-      ctor.prototype = null;
-      var result = func.apply(self, args.concat(slice.call(arguments)));
-      if (Object(result) === result) return result;
-      return self;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (!_.isFunction(func)) throw new TypeError('Bind must be called on a function');
+    var args = slice.call(arguments, 2);
+    var bound = function() {
+      return executeBound(func, bound, context, this, args.concat(slice.call(arguments)));
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return bound;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Partially apply a function by creating a version that has had some of its
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -628,49 +723,55 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // as a placeholder, allowing any combination of arguments to be pre-filled.
</span><span class="cx" style="display: block; padding: 0 10px">   _.partial = function(func) {
</span><span class="cx" style="display: block; padding: 0 10px">     var boundArgs = slice.call(arguments, 1);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return function() {
-      var position = 0;
-      var args = boundArgs.slice();
-      for (var i = 0, length = args.length; i < length; i++) {
-        if (args[i] === _) args[i] = arguments[position++];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var bound = function() {
+      var position = 0, length = boundArgs.length;
+      var args = Array(length);
+      for (var i = 0; i < length; i++) {
+        args[i] = boundArgs[i] === _ ? arguments[position++] : boundArgs[i];
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">       while (position < arguments.length) args.push(arguments[position++]);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return func.apply(this, args);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return executeBound(func, bound, this, this, args);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return bound;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Bind a number of an object's methods to that object. Remaining arguments
</span><span class="cx" style="display: block; padding: 0 10px">   // are the method names to be bound. Useful for ensuring that all callbacks
</span><span class="cx" style="display: block; padding: 0 10px">   // defined on an object belong to it.
</span><span class="cx" style="display: block; padding: 0 10px">   _.bindAll = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var funcs = slice.call(arguments, 1);
-    if (funcs.length === 0) throw new Error('bindAll must be passed function names');
-    each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var i, length = arguments.length, key;
+    if (length <= 1) throw new Error('bindAll must be passed function names');
+    for (i = 1; i < length; i++) {
+      key = arguments[i];
+      obj[key] = _.bind(obj[key], obj);
+    }
</ins><span class="cx" style="display: block; padding: 0 10px">     return obj;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Memoize an expensive function by storing its results.
</span><span class="cx" style="display: block; padding: 0 10px">   _.memoize = function(func, hasher) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var memo = {};
-    hasher || (hasher = _.identity);
-    return function() {
-      var key = hasher.apply(this, arguments);
-      return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var memoize = function(key) {
+      var cache = memoize.cache;
+      var address = '' + (hasher ? hasher.apply(this, arguments) : key);
+      if (!_.has(cache, address)) cache[address] = func.apply(this, arguments);
+      return cache[address];
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    memoize.cache = {};
+    return memoize;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Delays a function for the given number of milliseconds, and then calls
</span><span class="cx" style="display: block; padding: 0 10px">   // it with the arguments supplied.
</span><span class="cx" style="display: block; padding: 0 10px">   _.delay = function(func, wait) {
</span><span class="cx" style="display: block; padding: 0 10px">     var args = slice.call(arguments, 2);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return setTimeout(function(){ return func.apply(null, args); }, wait);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return setTimeout(function(){
+      return func.apply(null, args);
+    }, wait);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Defers a function, scheduling it to run after the current call stack has
</span><span class="cx" style="display: block; padding: 0 10px">   // cleared.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.defer = function(func) {
-    return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
-  };
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.defer = _.partial(_.delay, _, 1);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Returns a function, that, when invoked, will only be triggered at most once
</span><span class="cx" style="display: block; padding: 0 10px">   // during a given window of time. Normally, the throttled function will run
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -681,12 +782,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">     var context, args, result;
</span><span class="cx" style="display: block; padding: 0 10px">     var timeout = null;
</span><span class="cx" style="display: block; padding: 0 10px">     var previous = 0;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    options || (options = {});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (!options) options = {};
</ins><span class="cx" style="display: block; padding: 0 10px">     var later = function() {
</span><span class="cx" style="display: block; padding: 0 10px">       previous = options.leading === false ? 0 : _.now();
</span><span class="cx" style="display: block; padding: 0 10px">       timeout = null;
</span><span class="cx" style="display: block; padding: 0 10px">       result = func.apply(context, args);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      context = args = null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!timeout) context = args = null;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">     return function() {
</span><span class="cx" style="display: block; padding: 0 10px">       var now = _.now();
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -694,12 +795,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">       var remaining = wait - (now - previous);
</span><span class="cx" style="display: block; padding: 0 10px">       context = this;
</span><span class="cx" style="display: block; padding: 0 10px">       args = arguments;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (remaining <= 0) {
-        clearTimeout(timeout);
-        timeout = null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (remaining <= 0 || remaining > wait) {
+        if (timeout) {
+          clearTimeout(timeout);
+          timeout = null;
+        }
</ins><span class="cx" style="display: block; padding: 0 10px">         previous = now;
</span><span class="cx" style="display: block; padding: 0 10px">         result = func.apply(context, args);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        context = args = null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        if (!timeout) context = args = null;
</ins><span class="cx" style="display: block; padding: 0 10px">       } else if (!timeout && options.trailing !== false) {
</span><span class="cx" style="display: block; padding: 0 10px">         timeout = setTimeout(later, remaining);
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -716,13 +819,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     var later = function() {
</span><span class="cx" style="display: block; padding: 0 10px">       var last = _.now() - timestamp;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (last < wait) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      if (last < wait && last >= 0) {
</ins><span class="cx" style="display: block; padding: 0 10px">         timeout = setTimeout(later, wait - last);
</span><span class="cx" style="display: block; padding: 0 10px">       } else {
</span><span class="cx" style="display: block; padding: 0 10px">         timeout = null;
</span><span class="cx" style="display: block; padding: 0 10px">         if (!immediate) {
</span><span class="cx" style="display: block; padding: 0 10px">           result = func.apply(context, args);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-          context = args = null;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+          if (!timeout) context = args = null;
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -732,9 +836,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">       args = arguments;
</span><span class="cx" style="display: block; padding: 0 10px">       timestamp = _.now();
</span><span class="cx" style="display: block; padding: 0 10px">       var callNow = immediate && !timeout;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (!timeout) {
-        timeout = setTimeout(later, wait);
-      }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (!timeout) timeout = setTimeout(later, wait);
</ins><span class="cx" style="display: block; padding: 0 10px">       if (callNow) {
</span><span class="cx" style="display: block; padding: 0 10px">         result = func.apply(context, args);
</span><span class="cx" style="display: block; padding: 0 10px">         context = args = null;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -744,19 +846,6 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Returns a function that will be executed at most one time, no matter how
-  // often you call it. Useful for lazy initialization.
-  _.once = function(func) {
-    var ran = false, memo;
-    return function() {
-      if (ran) return memo;
-      ran = true;
-      memo = func.apply(this, arguments);
-      func = null;
-      return memo;
-    };
-  };
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Returns the first function passed as an argument to the second,
</span><span class="cx" style="display: block; padding: 0 10px">   // allowing you to adjust arguments, run code before and after, and
</span><span class="cx" style="display: block; padding: 0 10px">   // conditionally execute the original function.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -764,20 +853,27 @@
</span><span class="cx" style="display: block; padding: 0 10px">     return _.partial(wrapper, func);
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns a negated version of the passed-in predicate.
+  _.negate = function(predicate) {
+    return function() {
+      return !predicate.apply(this, arguments);
+    };
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Returns a function that is the composition of a list of functions, each
</span><span class="cx" style="display: block; padding: 0 10px">   // consuming the return value of the function that follows.
</span><span class="cx" style="display: block; padding: 0 10px">   _.compose = function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var funcs = arguments;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var args = arguments;
+    var start = args.length - 1;
</ins><span class="cx" style="display: block; padding: 0 10px">     return function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      var args = arguments;
-      for (var i = funcs.length - 1; i >= 0; i--) {
-        args = [funcs[i].apply(this, args)];
-      }
-      return args[0];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var i = start;
+      var result = args[start].apply(this, arguments);
+      while (i--) result = args[i].call(this, result);
+      return result;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Returns a function that will only be executed after being called N times.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns a function that will only be executed on and after the Nth call.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.after = function(times, func) {
</span><span class="cx" style="display: block; padding: 0 10px">     return function() {
</span><span class="cx" style="display: block; padding: 0 10px">       if (--times < 1) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -786,35 +882,100 @@
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns a function that will only be executed up to (but not including) the Nth call.
+  _.before = function(times, func) {
+    var memo;
+    return function() {
+      if (--times > 0) {
+        memo = func.apply(this, arguments);
+      }
+      if (times <= 1) func = null;
+      return memo;
+    };
+  };
+
+  // Returns a function that will be executed at most one time, no matter how
+  // often you call it. Useful for lazy initialization.
+  _.once = _.partial(_.before, 2);
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Object Functions
</span><span class="cx" style="display: block; padding: 0 10px">   // ----------------
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Retrieve the names of an object's properties.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Keys in IE < 9 that won't be iterated by `for key in ...` and thus missed.
+  var hasEnumBug = !{toString: null}.propertyIsEnumerable('toString');
+  var nonEnumerableProps = ['valueOf', 'isPrototypeOf', 'toString',
+                      'propertyIsEnumerable', 'hasOwnProperty', 'toLocaleString'];
+
+  function collectNonEnumProps(obj, keys) {
+    var nonEnumIdx = nonEnumerableProps.length;
+    var constructor = obj.constructor;
+    var proto = (_.isFunction(constructor) && constructor.prototype) || ObjProto;
+
+    // Constructor is a special case.
+    var prop = 'constructor';
+    if (_.has(obj, prop) && !_.contains(keys, prop)) keys.push(prop);
+
+    while (nonEnumIdx--) {
+      prop = nonEnumerableProps[nonEnumIdx];
+      if (prop in obj && obj[prop] !== proto[prop] && !_.contains(keys, prop)) {
+        keys.push(prop);
+      }
+    }
+  }
+
+  // Retrieve the names of an object's own properties.
</ins><span class="cx" style="display: block; padding: 0 10px">   // Delegates to **ECMAScript 5**'s native `Object.keys`
</span><span class="cx" style="display: block; padding: 0 10px">   _.keys = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (!_.isObject(obj)) return [];
</span><span class="cx" style="display: block; padding: 0 10px">     if (nativeKeys) return nativeKeys(obj);
</span><span class="cx" style="display: block; padding: 0 10px">     var keys = [];
</span><span class="cx" style="display: block; padding: 0 10px">     for (var key in obj) if (_.has(obj, key)) keys.push(key);
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Ahem, IE < 9.
+    if (hasEnumBug) collectNonEnumProps(obj, keys);
</ins><span class="cx" style="display: block; padding: 0 10px">     return keys;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Retrieve all the property names of an object.
+  _.allKeys = function(obj) {
+    if (!_.isObject(obj)) return [];
+    var keys = [];
+    for (var key in obj) keys.push(key);
+    // Ahem, IE < 9.
+    if (hasEnumBug) collectNonEnumProps(obj, keys);
+    return keys;
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Retrieve the values of an object's properties.
</span><span class="cx" style="display: block; padding: 0 10px">   _.values = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     var keys = _.keys(obj);
</span><span class="cx" style="display: block; padding: 0 10px">     var length = keys.length;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var values = new Array(length);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var values = Array(length);
</ins><span class="cx" style="display: block; padding: 0 10px">     for (var i = 0; i < length; i++) {
</span><span class="cx" style="display: block; padding: 0 10px">       values[i] = obj[keys[i]];
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px">     return values;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns the results of applying the iteratee to each element of the object
+  // In contrast to _.map it returns an object
+  _.mapObject = function(obj, iteratee, context) {
+    iteratee = cb(iteratee, context);
+    var keys =  _.keys(obj),
+          length = keys.length,
+          results = {},
+          currentKey;
+      for (var index = 0; index < length; index++) {
+        currentKey = keys[index];
+        results[currentKey] = iteratee(obj[currentKey], currentKey, obj);
+      }
+      return results;
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Convert an object into a list of `[key, value]` pairs.
</span><span class="cx" style="display: block; padding: 0 10px">   _.pairs = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     var keys = _.keys(obj);
</span><span class="cx" style="display: block; padding: 0 10px">     var length = keys.length;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var pairs = new Array(length);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var pairs = Array(length);
</ins><span class="cx" style="display: block; padding: 0 10px">     for (var i = 0; i < length; i++) {
</span><span class="cx" style="display: block; padding: 0 10px">       pairs[i] = [keys[i], obj[keys[i]]];
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -842,47 +1003,65 @@
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Extend a given object with all the properties in passed-in object(s).
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.extend = function(obj) {
-    each(slice.call(arguments, 1), function(source) {
-      if (source) {
-        for (var prop in source) {
-          obj[prop] = source[prop];
-        }
-      }
-    });
-    return obj;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.extend = createAssigner(_.allKeys);
+
+  // Assigns a given object with all the own properties in the passed-in object(s)
+  // (https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/assign)
+  _.extendOwn = _.assign = createAssigner(_.keys);
+
+  // Returns the first key on an object that passes a predicate test
+  _.findKey = function(obj, predicate, context) {
+    predicate = cb(predicate, context);
+    var keys = _.keys(obj), key;
+    for (var i = 0, length = keys.length; i < length; i++) {
+      key = keys[i];
+      if (predicate(obj[key], key, obj)) return key;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Return a copy of the object only containing the whitelisted properties.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.pick = function(obj) {
-    var copy = {};
-    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
-    each(keys, function(key) {
-      if (key in obj) copy[key] = obj[key];
-    });
-    return copy;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.pick = function(object, oiteratee, context) {
+    var result = {}, obj = object, iteratee, keys;
+    if (obj == null) return result;
+    if (_.isFunction(oiteratee)) {
+      keys = _.allKeys(obj);
+      iteratee = optimizeCb(oiteratee, context);
+    } else {
+      keys = flatten(arguments, false, false, 1);
+      iteratee = function(value, key, obj) { return key in obj; };
+      obj = Object(obj);
+    }
+    for (var i = 0, length = keys.length; i < length; i++) {
+      var key = keys[i];
+      var value = obj[key];
+      if (iteratee(value, key, obj)) result[key] = value;
+    }
+    return result;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">    // Return a copy of the object without the blacklisted properties.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.omit = function(obj) {
-    var copy = {};
-    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
-    for (var key in obj) {
-      if (!_.contains(keys, key)) copy[key] = obj[key];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.omit = function(obj, iteratee, context) {
+    if (_.isFunction(iteratee)) {
+      iteratee = _.negate(iteratee);
+    } else {
+      var keys = _.map(flatten(arguments, false, false, 1), String);
+      iteratee = function(value, key) {
+        return !_.contains(keys, key);
+      };
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return copy;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.pick(obj, iteratee, context);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Fill in a given object with default properties.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.defaults = function(obj) {
-    each(slice.call(arguments, 1), function(source) {
-      if (source) {
-        for (var prop in source) {
-          if (obj[prop] === void 0) obj[prop] = source[prop];
-        }
-      }
-    });
-    return obj;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.defaults = createAssigner(_.allKeys, true);
+
+  // Creates an object that inherits from the given prototype object.
+  // If additional properties are provided then they will be added to the
+  // created object.
+  _.create = function(prototype, props) {
+    var result = baseCreate(prototype);
+    if (props) _.extendOwn(result, props);
+    return result;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Create a (shallow-cloned) duplicate of an object.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -899,11 +1078,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">     return obj;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns whether an object has a given set of `key:value` pairs.
+  _.isMatch = function(object, attrs) {
+    var keys = _.keys(attrs), length = keys.length;
+    if (object == null) return !length;
+    var obj = Object(object);
+    for (var i = 0; i < length; i++) {
+      var key = keys[i];
+      if (attrs[key] !== obj[key] || !(key in obj)) return false;
+    }
+    return true;
+  };
+
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Internal recursive comparison function for `isEqual`.
</span><span class="cx" style="display: block; padding: 0 10px">   var eq = function(a, b, aStack, bStack) {
</span><span class="cx" style="display: block; padding: 0 10px">     // Identical objects are equal. `0 === -0`, but they aren't identical.
</span><span class="cx" style="display: block; padding: 0 10px">     // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (a === b) return a !== 0 || 1 / a == 1 / b;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (a === b) return a !== 0 || 1 / a === 1 / b;
</ins><span class="cx" style="display: block; padding: 0 10px">     // A strict comparison is necessary because `null == undefined`.
</span><span class="cx" style="display: block; padding: 0 10px">     if (a == null || b == null) return a === b;
</span><span class="cx" style="display: block; padding: 0 10px">     // Unwrap any wrapped objects.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -911,98 +1103,98 @@
</span><span class="cx" style="display: block; padding: 0 10px">     if (b instanceof _) b = b._wrapped;
</span><span class="cx" style="display: block; padding: 0 10px">     // Compare `[[Class]]` names.
</span><span class="cx" style="display: block; padding: 0 10px">     var className = toString.call(a);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (className != toString.call(b)) return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (className !== toString.call(b)) return false;
</ins><span class="cx" style="display: block; padding: 0 10px">     switch (className) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Strings, numbers, dates, and booleans are compared by value.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      // Strings, numbers, regular expressions, dates, and booleans are compared by value.
+      case '[object RegExp]':
+      // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
</ins><span class="cx" style="display: block; padding: 0 10px">       case '[object String]':
</span><span class="cx" style="display: block; padding: 0 10px">         // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
</span><span class="cx" style="display: block; padding: 0 10px">         // equivalent to `new String("5")`.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return a == String(b);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return '' + a === '' + b;
</ins><span class="cx" style="display: block; padding: 0 10px">       case '[object Number]':
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
-        // other numeric values.
-        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        // `NaN`s are equivalent, but non-reflexive.
+        // Object(NaN) is equivalent to NaN
+        if (+a !== +a) return +b !== +b;
+        // An `egal` comparison is performed for other numeric values.
+        return +a === 0 ? 1 / +a === 1 / b : +a === +b;
</ins><span class="cx" style="display: block; padding: 0 10px">       case '[object Date]':
</span><span class="cx" style="display: block; padding: 0 10px">       case '[object Boolean]':
</span><span class="cx" style="display: block; padding: 0 10px">         // Coerce dates and booleans to numeric primitive values. Dates are compared by their
</span><span class="cx" style="display: block; padding: 0 10px">         // millisecond representations. Note that invalid dates with millisecond representations
</span><span class="cx" style="display: block; padding: 0 10px">         // of `NaN` are not equivalent.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        return +a == +b;
-      // RegExps are compared by their source patterns and flags.
-      case '[object RegExp]':
-        return a.source == b.source &&
-               a.global == b.global &&
-               a.multiline == b.multiline &&
-               a.ignoreCase == b.ignoreCase;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        return +a === +b;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (typeof a != 'object' || typeof b != 'object') return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    var areArrays = className === '[object Array]';
+    if (!areArrays) {
+      if (typeof a != 'object' || typeof b != 'object') return false;
+
+      // Objects with different constructors are not equivalent, but `Object`s or `Array`s
+      // from different frames are.
+      var aCtor = a.constructor, bCtor = b.constructor;
+      if (aCtor !== bCtor && !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
+                               _.isFunction(bCtor) && bCtor instanceof bCtor)
+                          && ('constructor' in a && 'constructor' in b)) {
+        return false;
+      }
+    }
</ins><span class="cx" style="display: block; padding: 0 10px">     // Assume equality for cyclic structures. The algorithm for detecting cyclic
</span><span class="cx" style="display: block; padding: 0 10px">     // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+    // Initializing stack of traversed objects.
+    // It's done here since we only need them for objects and arrays comparison.
+    aStack = aStack || [];
+    bStack = bStack || [];
</ins><span class="cx" style="display: block; padding: 0 10px">     var length = aStack.length;
</span><span class="cx" style="display: block; padding: 0 10px">     while (length--) {
</span><span class="cx" style="display: block; padding: 0 10px">       // Linear search. Performance is inversely proportional to the number of
</span><span class="cx" style="display: block; padding: 0 10px">       // unique nested structures.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (aStack[length] == a) return bStack[length] == b;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if (aStack[length] === a) return bStack[length] === b;
</ins><span class="cx" style="display: block; padding: 0 10px">     }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Objects with different constructors are not equivalent, but `Object`s
-    // from different frames are.
-    var aCtor = a.constructor, bCtor = b.constructor;
-    if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
-                             _.isFunction(bCtor) && (bCtor instanceof bCtor))
-                        && ('constructor' in a && 'constructor' in b)) {
-      return false;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Add the first object to the stack of traversed objects.
</span><span class="cx" style="display: block; padding: 0 10px">     aStack.push(a);
</span><span class="cx" style="display: block; padding: 0 10px">     bStack.push(b);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var size = 0, result = true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
</ins><span class="cx" style="display: block; padding: 0 10px">     // Recursively compare objects and arrays.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (className == '[object Array]') {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (areArrays) {
</ins><span class="cx" style="display: block; padding: 0 10px">       // Compare array lengths to determine if a deep comparison is necessary.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      size = a.length;
-      result = size == b.length;
-      if (result) {
-        // Deep compare the contents, ignoring non-numeric properties.
-        while (size--) {
-          if (!(result = eq(a[size], b[size], aStack, bStack))) break;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      length = a.length;
+      if (length !== b.length) return false;
+      // Deep compare the contents, ignoring non-numeric properties.
+      while (length--) {
+        if (!eq(a[length], b[length], aStack, bStack)) return false;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><span class="cx" style="display: block; padding: 0 10px">     } else {
</span><span class="cx" style="display: block; padding: 0 10px">       // Deep compare objects.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      for (var key in a) {
-        if (_.has(a, key)) {
-          // Count the expected number of properties.
-          size++;
-          // Deep compare each member.
-          if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
-        }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var keys = _.keys(a), key;
+      length = keys.length;
+      // Ensure that both objects contain the same number of properties before comparing deep equality.
+      if (_.keys(b).length !== length) return false;
+      while (length--) {
+        // Deep compare each member
+        key = keys[length];
+        if (!(_.has(b, key) && eq(a[key], b[key], aStack, bStack))) return false;
</ins><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      // Ensure that both objects contain the same number of properties.
-      if (result) {
-        for (key in b) {
-          if (_.has(b, key) && !(size--)) break;
-        }
-        result = !size;
-      }
</del><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px">     // Remove the first object from the stack of traversed objects.
</span><span class="cx" style="display: block; padding: 0 10px">     aStack.pop();
</span><span class="cx" style="display: block; padding: 0 10px">     bStack.pop();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return result;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return true;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Perform a deep comparison to check if two objects are equal.
</span><span class="cx" style="display: block; padding: 0 10px">   _.isEqual = function(a, b) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return eq(a, b, [], []);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return eq(a, b);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Is a given array, string, or object empty?
</span><span class="cx" style="display: block; padding: 0 10px">   // An "empty" object has no enumerable own-properties.
</span><span class="cx" style="display: block; padding: 0 10px">   _.isEmpty = function(obj) {
</span><span class="cx" style="display: block; padding: 0 10px">     if (obj == null) return true;
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
-    for (var key in obj) if (_.has(obj, key)) return false;
-    return true;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    if (isArrayLike(obj) && (_.isArray(obj) || _.isString(obj) || _.isArguments(obj))) return obj.length === 0;
+    return _.keys(obj).length === 0;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Is a given value a DOM element?
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1013,33 +1205,35 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Is a given value an array?
</span><span class="cx" style="display: block; padding: 0 10px">   // Delegates to ECMA5's native Array.isArray
</span><span class="cx" style="display: block; padding: 0 10px">   _.isArray = nativeIsArray || function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return toString.call(obj) == '[object Array]';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return toString.call(obj) === '[object Array]';
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Is a given variable an object?
</span><span class="cx" style="display: block; padding: 0 10px">   _.isObject = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return obj === Object(obj);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var type = typeof obj;
+    return type === 'function' || type === 'object' && !!obj;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
-  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError.
+  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp', 'Error'], function(name) {
</ins><span class="cx" style="display: block; padding: 0 10px">     _['is' + name] = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return toString.call(obj) == '[object ' + name + ']';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return toString.call(obj) === '[object ' + name + ']';
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Define a fallback version of the method in browsers (ahem, IE), where
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Define a fallback version of the method in browsers (ahem, IE < 9), where
</ins><span class="cx" style="display: block; padding: 0 10px">   // there isn't any inspectable "Arguments" type.
</span><span class="cx" style="display: block; padding: 0 10px">   if (!_.isArguments(arguments)) {
</span><span class="cx" style="display: block; padding: 0 10px">     _.isArguments = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return !!(obj && _.has(obj, 'callee'));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return _.has(obj, 'callee');
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Optimize `isFunction` if appropriate.
-  if (typeof (/./) !== 'function') {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Optimize `isFunction` if appropriate. Work around some typeof bugs in old v8,
+  // IE 11 (#1621), and in Safari 8 (#1929).
+  if (typeof /./ != 'function' && typeof Int8Array != 'object') {
</ins><span class="cx" style="display: block; padding: 0 10px">     _.isFunction = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return typeof obj === 'function';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return typeof obj == 'function' || false;
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1050,12 +1244,12 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Is the given value `NaN`? (NaN is the only number which does not equal itself).
</span><span class="cx" style="display: block; padding: 0 10px">   _.isNaN = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return _.isNumber(obj) && obj != +obj;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return _.isNumber(obj) && obj !== +obj;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Is a given value a boolean?
</span><span class="cx" style="display: block; padding: 0 10px">   _.isBoolean = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Is a given value equal to null?
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1071,7 +1265,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // Shortcut function for checking if an object has a given property directly
</span><span class="cx" style="display: block; padding: 0 10px">   // on itself (in other words, not on a prototype).
</span><span class="cx" style="display: block; padding: 0 10px">   _.has = function(obj, key) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return hasOwnProperty.call(obj, key);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return obj != null && hasOwnProperty.call(obj, key);
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Utility Functions
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1084,39 +1278,43 @@
</span><span class="cx" style="display: block; padding: 0 10px">     return this;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Keep the identity function around for default iterators.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Keep the identity function around for default iteratees.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.identity = function(value) {
</span><span class="cx" style="display: block; padding: 0 10px">     return value;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Predicate-generating functions. Often useful outside of Underscore.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.constant = function(value) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return function () {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    return function() {
</ins><span class="cx" style="display: block; padding: 0 10px">       return value;
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.property = function(key) {
-    return function(obj) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.noop = function(){};
+
+  _.property = property;
+
+  // Generates a function for a given object that returns a given property.
+  _.propertyOf = function(obj) {
+    return obj == null ? function(){} : function(key) {
</ins><span class="cx" style="display: block; padding: 0 10px">       return obj[key];
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
-  _.matches = function(attrs) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Returns a predicate for checking whether an object has a given set of
+  // `key:value` pairs.
+  _.matcher = _.matches = function(attrs) {
+    attrs = _.extendOwn({}, attrs);
</ins><span class="cx" style="display: block; padding: 0 10px">     return function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if (obj === attrs) return true; //avoid comparing an object to itself.
-      for (var key in attrs) {
-        if (attrs[key] !== obj[key])
-          return false;
-      }
-      return true;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return _.isMatch(obj, attrs);
+    };
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Run a function **n** times.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.times = function(n, iterator, context) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.times = function(n, iteratee, context) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var accum = Array(Math.max(0, n));
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    iteratee = optimizeCb(iteratee, context, 1);
+    for (var i = 0; i < n; i++) accum[i] = iteratee(i);
</ins><span class="cx" style="display: block; padding: 0 10px">     return accum;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1130,56 +1328,48 @@
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // A (possibly faster) way to get the current timestamp as an integer.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.now = Date.now || function() { return new Date().getTime(); };
-
-  // List of HTML entities for escaping.
-  var entityMap = {
-    escape: {
-      '&': '&amp;',
-      '<': '&lt;',
-      '>': '&gt;',
-      '"': '&quot;',
-      "'": '&#x27;'
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.now = Date.now || function() {
+    return new Date().getTime();
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  entityMap.unescape = _.invert(entityMap.escape);
</del><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Regexes containing the keys and values listed immediately above.
-  var entityRegexes = {
-    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
-    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+   // List of HTML entities for escaping.
+  var escapeMap = {
+    '&': '&amp;',
+    '<': '&lt;',
+    '>': '&gt;',
+    '"': '&quot;',
+    "'": '&#x27;',
+    '`': '&#x60;'
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var unescapeMap = _.invert(escapeMap);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Functions for escaping and unescaping strings to/from HTML interpolation.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.each(['escape', 'unescape'], function(method) {
-    _[method] = function(string) {
-      if (string == null) return '';
-      return ('' + string).replace(entityRegexes[method], function(match) {
-        return entityMap[method][match];
-      });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var createEscaper = function(map) {
+    var escaper = function(match) {
+      return map[match];
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Regexes for identifying a key that needs to be escaped
+    var source = '(?:' + _.keys(map).join('|') + ')';
+    var testRegexp = RegExp(source);
+    var replaceRegexp = RegExp(source, 'g');
+    return function(string) {
+      string = string == null ? '' : '' + string;
+      return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+    };
+  };
+  _.escape = createEscaper(escapeMap);
+  _.unescape = createEscaper(unescapeMap);
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // If the value of the named `property` is a function then invoke it with the
</span><span class="cx" style="display: block; padding: 0 10px">   // `object` as context; otherwise, return it.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.result = function(object, property) {
-    if (object == null) return void 0;
-    var value = object[property];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.result = function(object, property, fallback) {
+    var value = object == null ? void 0 : object[property];
+    if (value === void 0) {
+      value = fallback;
+    }
</ins><span class="cx" style="display: block; padding: 0 10px">     return _.isFunction(value) ? value.call(object) : value;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Add your own custom functions to the Underscore object.
-  _.mixin = function(obj) {
-    each(_.functions(obj), function(name) {
-      var func = _[name] = obj[name];
-      _.prototype[name] = function() {
-        var args = [this._wrapped];
-        push.apply(args, arguments);
-        return result.call(this, func.apply(_, args));
-      };
-    });
-  };
-
</del><span class="cx" style="display: block; padding: 0 10px">   // Generate a unique integer id (unique within the entire client session).
</span><span class="cx" style="display: block; padding: 0 10px">   // Useful for temporary DOM ids.
</span><span class="cx" style="display: block; padding: 0 10px">   var idCounter = 0;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1208,22 +1398,26 @@
</span><span class="cx" style="display: block; padding: 0 10px">     '\\':     '\\',
</span><span class="cx" style="display: block; padding: 0 10px">     '\r':     'r',
</span><span class="cx" style="display: block; padding: 0 10px">     '\n':     'n',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    '\t':     't',
</del><span class="cx" style="display: block; padding: 0 10px">     '\u2028': 'u2028',
</span><span class="cx" style="display: block; padding: 0 10px">     '\u2029': 'u2029'
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var escapeChar = function(match) {
+    return '\\' + escapes[match];
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // JavaScript micro-templating, similar to John Resig's implementation.
</span><span class="cx" style="display: block; padding: 0 10px">   // Underscore templating handles arbitrary delimiters, preserves whitespace,
</span><span class="cx" style="display: block; padding: 0 10px">   // and correctly escapes quotes within interpolated code.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.template = function(text, data, settings) {
-    var render;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // NB: `oldSettings` only exists for backwards compatibility.
+  _.template = function(text, settings, oldSettings) {
+    if (!settings && oldSettings) settings = oldSettings;
</ins><span class="cx" style="display: block; padding: 0 10px">     settings = _.defaults({}, settings, _.templateSettings);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     // Combine delimiters into one regular expression via alternation.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    var matcher = new RegExp([
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var matcher = RegExp([
</ins><span class="cx" style="display: block; padding: 0 10px">       (settings.escape || noMatch).source,
</span><span class="cx" style="display: block; padding: 0 10px">       (settings.interpolate || noMatch).source,
</span><span class="cx" style="display: block; padding: 0 10px">       (settings.evaluate || noMatch).source
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1233,19 +1427,18 @@
</span><span class="cx" style="display: block; padding: 0 10px">     var index = 0;
</span><span class="cx" style="display: block; padding: 0 10px">     var source = "__p+='";
</span><span class="cx" style="display: block; padding: 0 10px">     text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      source += text.slice(index, offset)
-        .replace(escaper, function(match) { return '\\' + escapes[match]; });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      source += text.slice(index, offset).replace(escaper, escapeChar);
+      index = offset + match.length;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">       if (escape) {
</span><span class="cx" style="display: block; padding: 0 10px">         source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
-      if (interpolate) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else if (interpolate) {
</ins><span class="cx" style="display: block; padding: 0 10px">         source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      }
-      if (evaluate) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      } else if (evaluate) {
</ins><span class="cx" style="display: block; padding: 0 10px">         source += "';\n" + evaluate + "\n__p+='";
</span><span class="cx" style="display: block; padding: 0 10px">       }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      index = offset + match.length;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+      // Adobe VMs need the match returned to produce the correct offest.
</ins><span class="cx" style="display: block; padding: 0 10px">       return match;
</span><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px">     source += "';\n";
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1255,29 +1448,31 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     source = "var __t,__p='',__j=Array.prototype.join," +
</span><span class="cx" style="display: block; padding: 0 10px">       "print=function(){__p+=__j.call(arguments,'');};\n" +
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      source + "return __p;\n";
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      source + 'return __p;\n';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     try {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      render = new Function(settings.variable || 'obj', '_', source);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      var render = new Function(settings.variable || 'obj', '_', source);
</ins><span class="cx" style="display: block; padding: 0 10px">     } catch (e) {
</span><span class="cx" style="display: block; padding: 0 10px">       e.source = source;
</span><span class="cx" style="display: block; padding: 0 10px">       throw e;
</span><span class="cx" style="display: block; padding: 0 10px">     }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    if (data) return render(data, _);
</del><span class="cx" style="display: block; padding: 0 10px">     var template = function(data) {
</span><span class="cx" style="display: block; padding: 0 10px">       return render.call(this, data, _);
</span><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Provide the compiled function source as a convenience for precompilation.
-    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    // Provide the compiled source as a convenience for precompilation.
+    var argument = settings.variable || 'obj';
+    template.source = 'function(' + argument + '){\n' + source + '}';
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">     return template;
</span><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  // Add a "chain" function, which will delegate to the wrapper.
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Add a "chain" function. Start chaining a wrapped Underscore object.
</ins><span class="cx" style="display: block; padding: 0 10px">   _.chain = function(obj) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    return _(obj).chain();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+    var instance = _(obj);
+    instance._chain = true;
+    return instance;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // OOP
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1287,47 +1482,57 @@
</span><span class="cx" style="display: block; padding: 0 10px">   // underscore functions. Wrapped objects may be chained.
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Helper function to continue chaining intermediate results.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  var result = function(obj) {
-    return this._chain ? _(obj).chain() : obj;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  var result = function(instance, obj) {
+    return instance._chain ? _(obj).chain() : obj;
</ins><span class="cx" style="display: block; padding: 0 10px">   };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Add your own custom functions to the Underscore object.
+  _.mixin = function(obj) {
+    _.each(_.functions(obj), function(name) {
+      var func = _[name] = obj[name];
+      _.prototype[name] = function() {
+        var args = [this._wrapped];
+        push.apply(args, arguments);
+        return result(this, func.apply(_, args));
+      };
+    });
+  };
+
</ins><span class="cx" style="display: block; padding: 0 10px">   // Add all of the Underscore functions to the wrapper object.
</span><span class="cx" style="display: block; padding: 0 10px">   _.mixin(_);
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Add all mutator Array functions to the wrapper.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var method = ArrayProto[name];
</span><span class="cx" style="display: block; padding: 0 10px">     _.prototype[name] = function() {
</span><span class="cx" style="display: block; padding: 0 10px">       var obj = this._wrapped;
</span><span class="cx" style="display: block; padding: 0 10px">       method.apply(obj, arguments);
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
-      return result.call(this, obj);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+      return result(this, obj);
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">   // Add all accessor Array functions to the wrapper.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  each(['concat', 'join', 'slice'], function(name) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.each(['concat', 'join', 'slice'], function(name) {
</ins><span class="cx" style="display: block; padding: 0 10px">     var method = ArrayProto[name];
</span><span class="cx" style="display: block; padding: 0 10px">     _.prototype[name] = function() {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-      return result.call(this, method.apply(this._wrapped, arguments));
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+      return result(this, method.apply(this._wrapped, arguments));
</ins><span class="cx" style="display: block; padding: 0 10px">     };
</span><span class="cx" style="display: block; padding: 0 10px">   });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  _.extend(_.prototype, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Extracts the result from a wrapped and chained object.
+  _.prototype.value = function() {
+    return this._wrapped;
+  };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Start chaining a wrapped Underscore object.
-    chain: function() {
-      this._chain = true;
-      return this;
-    },
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  // Provide unwrapping proxy for some methods used in engine operations
+  // such as arithmetic and JSON stringification.
+  _.prototype.valueOf = _.prototype.toJSON = _.prototype.value;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-    // Extracts the result from a wrapped and chained object.
-    value: function() {
-      return this._wrapped;
-    }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+  _.prototype.toString = function() {
+    return '' + this._wrapped;
+  };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-  });
-
</del><span class="cx" style="display: block; padding: 0 10px">   // AMD registration happens at the end for compatibility with AMD loaders
</span><span class="cx" style="display: block; padding: 0 10px">   // that may not enforce next-turn semantics on modules. Even though general
</span><span class="cx" style="display: block; padding: 0 10px">   // practice for AMD registration is to be anonymous, underscore registers
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1340,4 +1545,4 @@
</span><span class="cx" style="display: block; padding: 0 10px">       return _;
</span><span class="cx" style="display: block; padding: 0 10px">     });
</span><span class="cx" style="display: block; padding: 0 10px">   }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-}).call(this);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+}.call(this));
</ins></span></pre></div>
<a id="trunksrcwpincludesjsunderscoreminjs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/js/underscore.min.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/js/underscore.min.js        2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/js/underscore.min.js  2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,5 +1,5 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//     Underscore.js 1.6.0
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+//     Underscore.js 1.8.3
</ins><span class="cx" style="display: block; padding: 0 10px"> //     http://underscorejs.org
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//     (c) 2009-2014 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+//     (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors
</ins><span class="cx" style="display: block; padding: 0 10px"> //     Underscore may be freely distributed under the MIT license.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-(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.f
 ilter===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.is
 Array(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(a
 rguments,"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(argumen
 ts,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]===voi
 d 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)&&&
 quot;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.i
 sArguments=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(){retu
 rn 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);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+(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&q
 uot;;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.i
 nject=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.m
 ap(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.throt
 tle=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):v
 oid 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]=f
 unction(){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);
</ins></span></pre></div>
<a id="trunksrcwpincludesscriptloaderphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/script-loader.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/script-loader.php   2016-02-17 15:02:03 UTC (rev 36545)
+++ trunk/src/wp-includes/script-loader.php     2016-02-17 15:21:09 UTC (rev 36546)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -314,8 +314,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">        $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2015-05-03' );
</span><span class="cx" style="display: block; padding: 0 10px">        did_action( 'init' ) && $scripts->add_data( 'json2', 'conditional', 'lt IE 8' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        $scripts->add( 'underscore', "/wp-includes/js/underscore$dev_suffix.js", array(), '1.6.0', 1 );
-       $scripts->add( 'backbone', "/wp-includes/js/backbone$dev_suffix.js", array( 'underscore','jquery' ), '1.1.2', 1 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ $scripts->add( 'underscore', "/wp-includes/js/underscore$dev_suffix.js", array(), '1.8.3', 1 );
+       $scripts->add( 'backbone', "/wp-includes/js/backbone$dev_suffix.js", array( 'underscore','jquery' ), '1.2.3', 1 );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        $scripts->add( 'wp-util', "/wp-includes/js/wp-util$suffix.js", array('underscore', 'jquery'), false, 1 );
</span><span class="cx" style="display: block; padding: 0 10px">        did_action( 'init' ) && $scripts->localize( 'wp-util', '_wpUtilSettings', array(
</span></span></pre>
</div>
</div>

</body>
</html>