Commit 873d1ad3

mo khan <mo@mokhan.ca>
2014-06-27 01:42:48
remove marionette rails gem and vendor marionette.js.
1 parent 586bd9b
vendor/assets/javascripts/backbone.babysitter.js
@@ -0,0 +1,190 @@
+// Backbone.BabySitter
+// -------------------
+// v0.1.4
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/marionettejs/backbone.babysitter
+
+(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(['backbone', 'underscore'], function(Backbone, _) {
+      return factory(Backbone, _);
+    });
+  } else if (typeof exports !== 'undefined') {
+    var Backbone = require('backbone');
+    var _ = require('underscore');
+    module.exports = factory(Backbone, _);
+  } else {
+    factory(root.Backbone, root._);
+  }
+
+}(this, function(Backbone, _) {
+  'use strict';
+
+  var previousChildViewContainer = Backbone.ChildViewContainer;
+
+  // BabySitter.ChildViewContainer
+  // -----------------------------
+  //
+  // Provide a container to store, retrieve and
+  // shut down child views.
+  
+  Backbone.ChildViewContainer = (function (Backbone, _) {
+  
+    // Container Constructor
+    // ---------------------
+  
+    var Container = function(views){
+      this._views = {};
+      this._indexByModel = {};
+      this._indexByCustom = {};
+      this._updateLength();
+  
+      _.each(views, this.add, this);
+    };
+  
+    // Container Methods
+    // -----------------
+  
+    _.extend(Container.prototype, {
+  
+      // Add a view to this container. Stores the view
+      // by `cid` and makes it searchable by the model
+      // cid (and model itself). Optionally specify
+      // a custom key to store an retrieve the view.
+      add: function(view, customIndex){
+        var viewCid = view.cid;
+  
+        // store the view
+        this._views[viewCid] = view;
+  
+        // index it by model
+        if (view.model){
+          this._indexByModel[view.model.cid] = viewCid;
+        }
+  
+        // index by custom
+        if (customIndex){
+          this._indexByCustom[customIndex] = viewCid;
+        }
+  
+        this._updateLength();
+        return this;
+      },
+  
+      // Find a view by the model that was attached to
+      // it. Uses the model's `cid` to find it.
+      findByModel: function(model){
+        return this.findByModelCid(model.cid);
+      },
+  
+      // Find a view by the `cid` of the model that was attached to
+      // it. Uses the model's `cid` to find the view `cid` and
+      // retrieve the view using it.
+      findByModelCid: function(modelCid){
+        var viewCid = this._indexByModel[modelCid];
+        return this.findByCid(viewCid);
+      },
+  
+      // Find a view by a custom indexer.
+      findByCustom: function(index){
+        var viewCid = this._indexByCustom[index];
+        return this.findByCid(viewCid);
+      },
+  
+      // Find by index. This is not guaranteed to be a
+      // stable index.
+      findByIndex: function(index){
+        return _.values(this._views)[index];
+      },
+  
+      // retrieve a view by its `cid` directly
+      findByCid: function(cid){
+        return this._views[cid];
+      },
+  
+      // Remove a view
+      remove: function(view){
+        var viewCid = view.cid;
+  
+        // delete model index
+        if (view.model){
+          delete this._indexByModel[view.model.cid];
+        }
+  
+        // delete custom index
+        _.any(this._indexByCustom, function(cid, key) {
+          if (cid === viewCid) {
+            delete this._indexByCustom[key];
+            return true;
+          }
+        }, this);
+  
+        // remove the view from the container
+        delete this._views[viewCid];
+  
+        // update the length
+        this._updateLength();
+        return this;
+      },
+  
+      // Call a method on every view in the container,
+      // passing parameters to the call method one at a
+      // time, like `function.call`.
+      call: function(method){
+        this.apply(method, _.tail(arguments));
+      },
+  
+      // Apply a method on every view in the container,
+      // passing parameters to the call method one at a
+      // time, like `function.apply`.
+      apply: function(method, args){
+        _.each(this._views, function(view){
+          if (_.isFunction(view[method])){
+            view[method].apply(view, args || []);
+          }
+        });
+      },
+  
+      // Update the `.length` attribute on this container
+      _updateLength: function(){
+        this.length = _.size(this._views);
+      }
+    });
+  
+    // Borrowing this code from Backbone.Collection:
+    // http://backbonejs.org/docs/backbone.html#section-106
+    //
+    // Mix in methods from Underscore, for iteration, and other
+    // collection related features.
+    var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
+      'select', 'reject', 'every', 'all', 'some', 'any', 'include',
+      'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
+      'last', 'without', 'isEmpty', 'pluck'];
+  
+    _.each(methods, function(method) {
+      Container.prototype[method] = function() {
+        var views = _.values(this._views);
+        var args = [views].concat(_.toArray(arguments));
+        return _[method].apply(_, args);
+      };
+    });
+  
+    // return the public API
+    return Container;
+  })(Backbone, _);
+  
+
+  Backbone.ChildViewContainer.VERSION = '0.1.4';
+
+  Backbone.ChildViewContainer.noConflict = function () {
+    Backbone.ChildViewContainer = previousChildViewContainer;
+    return this;
+  };
+
+  return Backbone.ChildViewContainer;
+
+}));
vendor/assets/javascripts/backbone.marionette.js
@@ -0,0 +1,3254 @@
+// MarionetteJS (Backbone.Marionette)
+// ----------------------------------
+// v2.0.1
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://marionettejs.com
+
+
+/*!
+ * Includes BabySitter
+ * https://github.com/marionettejs/backbone.babysitter/
+ *
+ * Includes Wreqr
+ * https://github.com/marionettejs/backbone.wreqr/
+ */
+
+
+(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(['backbone', 'underscore'], function(Backbone, _) {
+      return (root.Marionette = factory(root, Backbone, _));
+    });
+  } else if (typeof exports !== 'undefined') {
+    var Backbone = require('backbone');
+    var _ = require('underscore');
+    module.exports = factory(root, Backbone, _);
+  } else {
+    root.Marionette = factory(root, root.Backbone, root._);
+  }
+
+}(this, function(root, Backbone, _) {
+  'use strict';
+
+  // Backbone.BabySitter
+  // -------------------
+  // v0.1.4
+  //
+  // Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+  // Distributed under MIT license
+  //
+  // http://github.com/marionettejs/backbone.babysitter
+  (function(Backbone, _) {
+    "use strict";
+    var previousChildViewContainer = Backbone.ChildViewContainer;
+    // BabySitter.ChildViewContainer
+    // -----------------------------
+    //
+    // Provide a container to store, retrieve and
+    // shut down child views.
+    Backbone.ChildViewContainer = function(Backbone, _) {
+      // Container Constructor
+      // ---------------------
+      var Container = function(views) {
+        this._views = {};
+        this._indexByModel = {};
+        this._indexByCustom = {};
+        this._updateLength();
+        _.each(views, this.add, this);
+      };
+      // Container Methods
+      // -----------------
+      _.extend(Container.prototype, {
+        // Add a view to this container. Stores the view
+        // by `cid` and makes it searchable by the model
+        // cid (and model itself). Optionally specify
+        // a custom key to store an retrieve the view.
+        add: function(view, customIndex) {
+          var viewCid = view.cid;
+          // store the view
+          this._views[viewCid] = view;
+          // index it by model
+          if (view.model) {
+            this._indexByModel[view.model.cid] = viewCid;
+          }
+          // index by custom
+          if (customIndex) {
+            this._indexByCustom[customIndex] = viewCid;
+          }
+          this._updateLength();
+          return this;
+        },
+        // Find a view by the model that was attached to
+        // it. Uses the model's `cid` to find it.
+        findByModel: function(model) {
+          return this.findByModelCid(model.cid);
+        },
+        // Find a view by the `cid` of the model that was attached to
+        // it. Uses the model's `cid` to find the view `cid` and
+        // retrieve the view using it.
+        findByModelCid: function(modelCid) {
+          var viewCid = this._indexByModel[modelCid];
+          return this.findByCid(viewCid);
+        },
+        // Find a view by a custom indexer.
+        findByCustom: function(index) {
+          var viewCid = this._indexByCustom[index];
+          return this.findByCid(viewCid);
+        },
+        // Find by index. This is not guaranteed to be a
+        // stable index.
+        findByIndex: function(index) {
+          return _.values(this._views)[index];
+        },
+        // retrieve a view by its `cid` directly
+        findByCid: function(cid) {
+          return this._views[cid];
+        },
+        // Remove a view
+        remove: function(view) {
+          var viewCid = view.cid;
+          // delete model index
+          if (view.model) {
+            delete this._indexByModel[view.model.cid];
+          }
+          // delete custom index
+          _.any(this._indexByCustom, function(cid, key) {
+            if (cid === viewCid) {
+              delete this._indexByCustom[key];
+              return true;
+            }
+          }, this);
+          // remove the view from the container
+          delete this._views[viewCid];
+          // update the length
+          this._updateLength();
+          return this;
+        },
+        // Call a method on every view in the container,
+        // passing parameters to the call method one at a
+        // time, like `function.call`.
+        call: function(method) {
+          this.apply(method, _.tail(arguments));
+        },
+        // Apply a method on every view in the container,
+        // passing parameters to the call method one at a
+        // time, like `function.apply`.
+        apply: function(method, args) {
+          _.each(this._views, function(view) {
+            if (_.isFunction(view[method])) {
+              view[method].apply(view, args || []);
+            }
+          });
+        },
+        // Update the `.length` attribute on this container
+        _updateLength: function() {
+          this.length = _.size(this._views);
+        }
+      });
+      // Borrowing this code from Backbone.Collection:
+      // http://backbonejs.org/docs/backbone.html#section-106
+      //
+      // Mix in methods from Underscore, for iteration, and other
+      // collection related features.
+      var methods = [ "forEach", "each", "map", "find", "detect", "filter", "select", "reject", "every", "all", "some", "any", "include", "contains", "invoke", "toArray", "first", "initial", "rest", "last", "without", "isEmpty", "pluck" ];
+      _.each(methods, function(method) {
+        Container.prototype[method] = function() {
+          var views = _.values(this._views);
+          var args = [ views ].concat(_.toArray(arguments));
+          return _[method].apply(_, args);
+        };
+      });
+      // return the public API
+      return Container;
+    }(Backbone, _);
+    Backbone.ChildViewContainer.VERSION = "0.1.4";
+    Backbone.ChildViewContainer.noConflict = function() {
+      Backbone.ChildViewContainer = previousChildViewContainer;
+      return this;
+    };
+    return Backbone.ChildViewContainer;
+  })(Backbone, _);
+  // Backbone.Wreqr (Backbone.Marionette)
+  // ----------------------------------
+  // v1.3.1
+  //
+  // Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+  // Distributed under MIT license
+  //
+  // http://github.com/marionettejs/backbone.wreqr
+  (function(Backbone, _) {
+    "use strict";
+    var previousWreqr = Backbone.Wreqr;
+    var Wreqr = Backbone.Wreqr = {};
+    Backbone.Wreqr.VERSION = "1.3.1";
+    Backbone.Wreqr.noConflict = function() {
+      Backbone.Wreqr = previousWreqr;
+      return this;
+    };
+    // Handlers
+    // --------
+    // A registry of functions to call, given a name
+    Wreqr.Handlers = function(Backbone, _) {
+      "use strict";
+      // Constructor
+      // -----------
+      var Handlers = function(options) {
+        this.options = options;
+        this._wreqrHandlers = {};
+        if (_.isFunction(this.initialize)) {
+          this.initialize(options);
+        }
+      };
+      Handlers.extend = Backbone.Model.extend;
+      // Instance Members
+      // ----------------
+      _.extend(Handlers.prototype, Backbone.Events, {
+        // Add multiple handlers using an object literal configuration
+        setHandlers: function(handlers) {
+          _.each(handlers, function(handler, name) {
+            var context = null;
+            if (_.isObject(handler) && !_.isFunction(handler)) {
+              context = handler.context;
+              handler = handler.callback;
+            }
+            this.setHandler(name, handler, context);
+          }, this);
+        },
+        // Add a handler for the given name, with an
+        // optional context to run the handler within
+        setHandler: function(name, handler, context) {
+          var config = {
+            callback: handler,
+            context: context
+          };
+          this._wreqrHandlers[name] = config;
+          this.trigger("handler:add", name, handler, context);
+        },
+        // Determine whether or not a handler is registered
+        hasHandler: function(name) {
+          return !!this._wreqrHandlers[name];
+        },
+        // Get the currently registered handler for
+        // the specified name. Throws an exception if
+        // no handler is found.
+        getHandler: function(name) {
+          var config = this._wreqrHandlers[name];
+          if (!config) {
+            return;
+          }
+          return function() {
+            var args = Array.prototype.slice.apply(arguments);
+            return config.callback.apply(config.context, args);
+          };
+        },
+        // Remove a handler for the specified name
+        removeHandler: function(name) {
+          delete this._wreqrHandlers[name];
+        },
+        // Remove all handlers from this registry
+        removeAllHandlers: function() {
+          this._wreqrHandlers = {};
+        }
+      });
+      return Handlers;
+    }(Backbone, _);
+    // Wreqr.CommandStorage
+    // --------------------
+    //
+    // Store and retrieve commands for execution.
+    Wreqr.CommandStorage = function() {
+      "use strict";
+      // Constructor function
+      var CommandStorage = function(options) {
+        this.options = options;
+        this._commands = {};
+        if (_.isFunction(this.initialize)) {
+          this.initialize(options);
+        }
+      };
+      // Instance methods
+      _.extend(CommandStorage.prototype, Backbone.Events, {
+        // Get an object literal by command name, that contains
+        // the `commandName` and the `instances` of all commands
+        // represented as an array of arguments to process
+        getCommands: function(commandName) {
+          var commands = this._commands[commandName];
+          // we don't have it, so add it
+          if (!commands) {
+            // build the configuration
+            commands = {
+              command: commandName,
+              instances: []
+            };
+            // store it
+            this._commands[commandName] = commands;
+          }
+          return commands;
+        },
+        // Add a command by name, to the storage and store the
+        // args for the command
+        addCommand: function(commandName, args) {
+          var command = this.getCommands(commandName);
+          command.instances.push(args);
+        },
+        // Clear all commands for the given `commandName`
+        clearCommands: function(commandName) {
+          var command = this.getCommands(commandName);
+          command.instances = [];
+        }
+      });
+      return CommandStorage;
+    }();
+    // Wreqr.Commands
+    // --------------
+    //
+    // A simple command pattern implementation. Register a command
+    // handler and execute it.
+    Wreqr.Commands = function(Wreqr) {
+      "use strict";
+      return Wreqr.Handlers.extend({
+        // default storage type
+        storageType: Wreqr.CommandStorage,
+        constructor: function(options) {
+          this.options = options || {};
+          this._initializeStorage(this.options);
+          this.on("handler:add", this._executeCommands, this);
+          var args = Array.prototype.slice.call(arguments);
+          Wreqr.Handlers.prototype.constructor.apply(this, args);
+        },
+        // Execute a named command with the supplied args
+        execute: function(name, args) {
+          name = arguments[0];
+          args = Array.prototype.slice.call(arguments, 1);
+          if (this.hasHandler(name)) {
+            this.getHandler(name).apply(this, args);
+          } else {
+            this.storage.addCommand(name, args);
+          }
+        },
+        // Internal method to handle bulk execution of stored commands
+        _executeCommands: function(name, handler, context) {
+          var command = this.storage.getCommands(name);
+          // loop through and execute all the stored command instances
+          _.each(command.instances, function(args) {
+            handler.apply(context, args);
+          });
+          this.storage.clearCommands(name);
+        },
+        // Internal method to initialize storage either from the type's
+        // `storageType` or the instance `options.storageType`.
+        _initializeStorage: function(options) {
+          var storage;
+          var StorageType = options.storageType || this.storageType;
+          if (_.isFunction(StorageType)) {
+            storage = new StorageType();
+          } else {
+            storage = StorageType;
+          }
+          this.storage = storage;
+        }
+      });
+    }(Wreqr);
+    // Wreqr.RequestResponse
+    // ---------------------
+    //
+    // A simple request/response implementation. Register a
+    // request handler, and return a response from it
+    Wreqr.RequestResponse = function(Wreqr) {
+      "use strict";
+      return Wreqr.Handlers.extend({
+        request: function() {
+          var name = arguments[0];
+          var args = Array.prototype.slice.call(arguments, 1);
+          if (this.hasHandler(name)) {
+            return this.getHandler(name).apply(this, args);
+          }
+        }
+      });
+    }(Wreqr);
+    // Event Aggregator
+    // ----------------
+    // A pub-sub object that can be used to decouple various parts
+    // of an application through event-driven architecture.
+    Wreqr.EventAggregator = function(Backbone, _) {
+      "use strict";
+      var EA = function() {};
+      // Copy the `extend` function used by Backbone's classes
+      EA.extend = Backbone.Model.extend;
+      // Copy the basic Backbone.Events on to the event aggregator
+      _.extend(EA.prototype, Backbone.Events);
+      return EA;
+    }(Backbone, _);
+    // Wreqr.Channel
+    // --------------
+    //
+    // An object that wraps the three messaging systems:
+    // EventAggregator, RequestResponse, Commands
+    Wreqr.Channel = function(Wreqr) {
+      "use strict";
+      var Channel = function(channelName) {
+        this.vent = new Backbone.Wreqr.EventAggregator();
+        this.reqres = new Backbone.Wreqr.RequestResponse();
+        this.commands = new Backbone.Wreqr.Commands();
+        this.channelName = channelName;
+      };
+      _.extend(Channel.prototype, {
+        // Remove all handlers from the messaging systems of this channel
+        reset: function() {
+          this.vent.off();
+          this.vent.stopListening();
+          this.reqres.removeAllHandlers();
+          this.commands.removeAllHandlers();
+          return this;
+        },
+        // Connect a hash of events; one for each messaging system
+        connectEvents: function(hash, context) {
+          this._connect("vent", hash, context);
+          return this;
+        },
+        connectCommands: function(hash, context) {
+          this._connect("commands", hash, context);
+          return this;
+        },
+        connectRequests: function(hash, context) {
+          this._connect("reqres", hash, context);
+          return this;
+        },
+        // Attach the handlers to a given message system `type`
+        _connect: function(type, hash, context) {
+          if (!hash) {
+            return;
+          }
+          context = context || this;
+          var method = type === "vent" ? "on" : "setHandler";
+          _.each(hash, function(fn, eventName) {
+            this[type][method](eventName, _.bind(fn, context));
+          }, this);
+        }
+      });
+      return Channel;
+    }(Wreqr);
+    // Wreqr.Radio
+    // --------------
+    //
+    // An object that lets you communicate with many channels.
+    Wreqr.radio = function(Wreqr) {
+      "use strict";
+      var Radio = function() {
+        this._channels = {};
+        this.vent = {};
+        this.commands = {};
+        this.reqres = {};
+        this._proxyMethods();
+      };
+      _.extend(Radio.prototype, {
+        channel: function(channelName) {
+          if (!channelName) {
+            throw new Error("Channel must receive a name");
+          }
+          return this._getChannel(channelName);
+        },
+        _getChannel: function(channelName) {
+          var channel = this._channels[channelName];
+          if (!channel) {
+            channel = new Wreqr.Channel(channelName);
+            this._channels[channelName] = channel;
+          }
+          return channel;
+        },
+        _proxyMethods: function() {
+          _.each([ "vent", "commands", "reqres" ], function(system) {
+            _.each(messageSystems[system], function(method) {
+              this[system][method] = proxyMethod(this, system, method);
+            }, this);
+          }, this);
+        }
+      });
+      var messageSystems = {
+        vent: [ "on", "off", "trigger", "once", "stopListening", "listenTo", "listenToOnce" ],
+        commands: [ "execute", "setHandler", "setHandlers", "removeHandler", "removeAllHandlers" ],
+        reqres: [ "request", "setHandler", "setHandlers", "removeHandler", "removeAllHandlers" ]
+      };
+      var proxyMethod = function(radio, system, method) {
+        return function(channelName) {
+          var messageSystem = radio._getChannel(channelName)[system];
+          var args = Array.prototype.slice.call(arguments, 1);
+          return messageSystem[method].apply(messageSystem, args);
+        };
+      };
+      return new Radio();
+    }(Wreqr);
+    return Backbone.Wreqr;
+  })(Backbone, _);
+
+  var previousMarionette = root.Marionette;
+
+  var Marionette = Backbone.Marionette = {};
+
+  Marionette.VERSION = '2.0.1';
+
+  Marionette.noConflict = function() {
+    root.Marionette = previousMarionette;
+    return this;
+  };
+
+  Backbone.Marionette = Marionette;
+
+  // Get the Deferred creator for later use
+  Marionette.Deferred = Backbone.$.Deferred;
+
+  /* jshint unused: false */
+  
+  // Helpers
+  // -------
+  
+  // For slicing `arguments` in functions
+  var slice = Array.prototype.slice;
+  
+  function throwError(message, name) {
+    var error = new Error(message);
+    error.name = name || 'Error';
+    throw error;
+  }
+  
+  // Marionette.extend
+  // -----------------
+  
+  // Borrow the Backbone `extend` method so we can use it as needed
+  Marionette.extend = Backbone.Model.extend;
+  
+  // Marionette.getOption
+  // --------------------
+  
+  // Retrieve an object, function or other value from a target
+  // object or its `options`, with `options` taking precedence.
+  Marionette.getOption = function(target, optionName) {
+    if (!target || !optionName) { return; }
+    var value;
+  
+    if (target.options && (target.options[optionName] !== undefined)) {
+      value = target.options[optionName];
+    } else {
+      value = target[optionName];
+    }
+  
+    return value;
+  };
+  
+  // Proxy `Marionette.getOption`
+  Marionette.proxyGetOption = function(optionName) {
+    return Marionette.getOption(this, optionName);
+  };
+  
+  // Marionette.normalizeMethods
+  // ----------------------
+  
+  // Pass in a mapping of events => functions or function names
+  // and return a mapping of events => functions
+  Marionette.normalizeMethods = function(hash) {
+    var normalizedHash = {}, method;
+    _.each(hash, function(fn, name) {
+      method = fn;
+      if (!_.isFunction(method)) {
+        method = this[method];
+      }
+      if (!method) {
+        return;
+      }
+      normalizedHash[name] = method;
+    }, this);
+    return normalizedHash;
+  };
+  
+  
+  // allows for the use of the @ui. syntax within
+  // a given key for triggers and events
+  // swaps the @ui with the associated selector
+  Marionette.normalizeUIKeys = function(hash, ui) {
+    if (typeof(hash) === 'undefined') {
+      return;
+    }
+  
+    _.each(_.keys(hash), function(v) {
+      var pattern = /@ui.[a-zA-Z_$0-9]*/g;
+      if (v.match(pattern)) {
+        hash[v.replace(pattern, function(r) {
+          return ui[r.slice(4)];
+        })] = hash[v];
+        delete hash[v];
+      }
+    });
+  
+    return hash;
+  };
+  
+  // Mix in methods from Underscore, for iteration, and other
+  // collection related features.
+  // Borrowing this code from Backbone.Collection:
+  // http://backbonejs.org/docs/backbone.html#section-106
+  Marionette.actAsCollection = function(object, listProperty) {
+    var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
+      'select', 'reject', 'every', 'all', 'some', 'any', 'include',
+      'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
+      'last', 'without', 'isEmpty', 'pluck'];
+  
+    _.each(methods, function(method) {
+      object[method] = function() {
+        var list = _.values(_.result(this, listProperty));
+        var args = [list].concat(_.toArray(arguments));
+        return _[method].apply(_, args);
+      };
+    });
+  };
+  
+  // Trigger an event and/or a corresponding method name. Examples:
+  //
+  // `this.triggerMethod("foo")` will trigger the "foo" event and
+  // call the "onFoo" method.
+  //
+  // `this.triggerMethod("foo:bar")` will trigger the "foo:bar" event and
+  // call the "onFooBar" method.
+  Marionette.triggerMethod = (function() {
+  
+    // split the event name on the ":"
+    var splitter = /(^|:)(\w)/gi;
+  
+    // take the event section ("section1:section2:section3")
+    // and turn it in to uppercase name
+    function getEventName(match, prefix, eventName) {
+      return eventName.toUpperCase();
+    }
+  
+    // actual triggerMethod implementation
+    var triggerMethod = function(event) {
+      // get the method name from the event name
+      var methodName = 'on' + event.replace(splitter, getEventName);
+      var method = this[methodName];
+      var result;
+  
+      // call the onMethodName if it exists
+      if (_.isFunction(method)) {
+        // pass all arguments, except the event name
+        result = method.apply(this, _.tail(arguments));
+      }
+  
+      // trigger the event, if a trigger method exists
+      if (_.isFunction(this.trigger)) {
+        this.trigger.apply(this, arguments);
+      }
+  
+      return result;
+    };
+  
+    return triggerMethod;
+  })();
+  
+  // DOMRefresh
+  // ----------
+  //
+  // Monitor a view's state, and after it has been rendered and shown
+  // in the DOM, trigger a "dom:refresh" event every time it is
+  // re-rendered.
+  
+  Marionette.MonitorDOMRefresh = (function(documentElement) {
+    // track when the view has been shown in the DOM,
+    // using a Marionette.Region (or by other means of triggering "show")
+    function handleShow(view) {
+      view._isShown = true;
+      triggerDOMRefresh(view);
+    }
+  
+    // track when the view has been rendered
+    function handleRender(view) {
+      view._isRendered = true;
+      triggerDOMRefresh(view);
+    }
+  
+    // Trigger the "dom:refresh" event and corresponding "onDomRefresh" method
+    function triggerDOMRefresh(view) {
+      if (view._isShown && view._isRendered && isInDOM(view)) {
+        if (_.isFunction(view.triggerMethod)) {
+          view.triggerMethod('dom:refresh');
+        }
+      }
+    }
+  
+    function isInDOM(view) {
+      return documentElement.contains(view.el);
+    }
+  
+    // Export public API
+    return function(view) {
+      view.listenTo(view, 'show', function() {
+        handleShow(view);
+      });
+  
+      view.listenTo(view, 'render', function() {
+        handleRender(view);
+      });
+    };
+  })(document.documentElement);
+  
+
+  /* jshint maxparams: 5 */
+  
+  // Marionette.bindEntityEvents & unbindEntityEvents
+  // ---------------------------
+  //
+  // These methods are used to bind/unbind a backbone "entity" (collection/model)
+  // to methods on a target object.
+  //
+  // The first parameter, `target`, must have a `listenTo` method from the
+  // EventBinder object.
+  //
+  // The second parameter is the entity (Backbone.Model or Backbone.Collection)
+  // to bind the events from.
+  //
+  // The third parameter is a hash of { "event:name": "eventHandler" }
+  // configuration. Multiple handlers can be separated by a space. A
+  // function can be supplied instead of a string handler name.
+  
+  (function(Marionette) {
+    'use strict';
+  
+    // Bind the event to handlers specified as a string of
+    // handler names on the target object
+    function bindFromStrings(target, entity, evt, methods) {
+      var methodNames = methods.split(/\s+/);
+  
+      _.each(methodNames, function(methodName) {
+  
+        var method = target[methodName];
+        if (!method) {
+          throwError('Method "' + methodName +
+            '" was configured as an event handler, but does not exist.');
+        }
+  
+        target.listenTo(entity, evt, method);
+      });
+    }
+  
+    // Bind the event to a supplied callback function
+    function bindToFunction(target, entity, evt, method) {
+      target.listenTo(entity, evt, method);
+    }
+  
+    // Bind the event to handlers specified as a string of
+    // handler names on the target object
+    function unbindFromStrings(target, entity, evt, methods) {
+      var methodNames = methods.split(/\s+/);
+  
+      _.each(methodNames, function(methodName) {
+        var method = target[methodName];
+        target.stopListening(entity, evt, method);
+      });
+    }
+  
+    // Bind the event to a supplied callback function
+    function unbindToFunction(target, entity, evt, method) {
+      target.stopListening(entity, evt, method);
+    }
+  
+  
+    // generic looping function
+    function iterateEvents(target, entity, bindings, functionCallback, stringCallback) {
+      if (!entity || !bindings) { return; }
+  
+      // allow the bindings to be a function
+      if (_.isFunction(bindings)) {
+        bindings = bindings.call(target);
+      }
+  
+      // iterate the bindings and bind them
+      _.each(bindings, function(methods, evt) {
+  
+        // allow for a function as the handler,
+        // or a list of event names as a string
+        if (_.isFunction(methods)) {
+          functionCallback(target, entity, evt, methods);
+        } else {
+          stringCallback(target, entity, evt, methods);
+        }
+  
+      });
+    }
+  
+    // Export Public API
+    Marionette.bindEntityEvents = function(target, entity, bindings) {
+      iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings);
+    };
+  
+    Marionette.unbindEntityEvents = function(target, entity, bindings) {
+      iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings);
+    };
+  
+    // Proxy `bindEntityEvents`
+    Marionette.proxyBindEntityEvents = function(entity, bindings) {
+      return Marionette.bindEntityEvents(this, entity, bindings);
+    };
+  
+    // Proxy `unbindEntityEvents`
+    Marionette.proxyUnbindEntityEvents = function(entity, bindings) {
+      return Marionette.unbindEntityEvents(this, entity, bindings);
+    };
+  })(Marionette);
+  
+
+  // Callbacks
+  // ---------
+  
+  // A simple way of managing a collection of callbacks
+  // and executing them at a later point in time, using jQuery's
+  // `Deferred` object.
+  Marionette.Callbacks = function() {
+    this._deferred = Marionette.Deferred();
+    this._callbacks = [];
+  };
+  
+  _.extend(Marionette.Callbacks.prototype, {
+  
+    // Add a callback to be executed. Callbacks added here are
+    // guaranteed to execute, even if they are added after the
+    // `run` method is called.
+    add: function(callback, contextOverride) {
+      var promise = _.result(this._deferred, 'promise');
+  
+      this._callbacks.push({cb: callback, ctx: contextOverride});
+  
+      promise.then(function(args) {
+        if (contextOverride){ args.context = contextOverride; }
+        callback.call(args.context, args.options);
+      });
+    },
+  
+    // Run all registered callbacks with the context specified.
+    // Additional callbacks can be added after this has been run
+    // and they will still be executed.
+    run: function(options, context) {
+      this._deferred.resolve({
+        options: options,
+        context: context
+      });
+    },
+  
+    // Resets the list of callbacks to be run, allowing the same list
+    // to be run multiple times - whenever the `run` method is called.
+    reset: function() {
+      var callbacks = this._callbacks;
+      this._deferred = Marionette.Deferred();
+      this._callbacks = [];
+  
+      _.each(callbacks, function(cb) {
+        this.add(cb.cb, cb.ctx);
+      }, this);
+    }
+  });
+  
+  // Marionette Controller
+  // ---------------------
+  //
+  // A multi-purpose object to use as a controller for
+  // modules and routers, and as a mediator for workflow
+  // and coordination of other objects, views, and more.
+  Marionette.Controller = function(options) {
+    this.triggerMethod = Marionette.triggerMethod;
+    this.options = options || {};
+  
+    if (_.isFunction(this.initialize)) {
+      this.initialize(this.options);
+    }
+  };
+  
+  Marionette.Controller.extend = Marionette.extend;
+  
+  // Controller Methods
+  // --------------
+  
+  // Ensure it can trigger events with Backbone.Events
+  _.extend(Marionette.Controller.prototype, Backbone.Events, {
+    destroy: function() {
+      var args = Array.prototype.slice.call(arguments);
+      this.triggerMethod.apply(this, ['before:destroy'].concat(args));
+      this.triggerMethod.apply(this, ['destroy'].concat(args));
+  
+      this.stopListening();
+      this.off();
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod,
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption
+  
+  });
+  
+  /* jshint maxcomplexity: 10, maxstatements: 27 */
+  
+  // Region
+  // ------
+  //
+  // Manage the visual regions of your composite application. See
+  // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/
+  
+  Marionette.Region = function(options) {
+    this.options = options || {};
+    this.el = this.getOption('el');
+  
+    // Handle when this.el is passed in as a $ wrapped element.
+    this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;
+  
+    if (!this.el) {
+      throwError('An "el" must be specified for a region.', 'NoElError');
+    }
+  
+    this.$el = this.getEl(this.el);
+  
+    if (this.initialize) {
+      var args = Array.prototype.slice.apply(arguments);
+      this.initialize.apply(this, args);
+    }
+  };
+  
+  
+  // Region Class methods
+  // -------------------
+  
+  _.extend(Marionette.Region, {
+  
+    // Build an instance of a region by passing in a configuration object
+    // and a default region class to use if none is specified in the config.
+    //
+    // The config object should either be a string as a jQuery DOM selector,
+    // a Region class directly, or an object literal that specifies both
+    // a selector and regionClass:
+    //
+    // ```js
+    // {
+    //   selector: "#foo",
+    //   regionClass: MyCustomRegion
+    // }
+    // ```
+    //
+    buildRegion: function(regionConfig, defaultRegionClass) {
+      var regionIsString = _.isString(regionConfig);
+      var regionSelectorIsString = _.isString(regionConfig.selector);
+      var regionClassIsUndefined = _.isUndefined(regionConfig.regionClass);
+      var regionIsClass = _.isFunction(regionConfig);
+  
+      if (!regionIsClass && !regionIsString && !regionSelectorIsString) {
+        throwError('Region must be specified as a Region class,' +
+          'a selector string or an object with selector property');
+      }
+  
+      var selector, RegionClass;
+  
+      // get the selector for the region
+  
+      if (regionIsString) {
+        selector = regionConfig;
+      }
+  
+      if (regionConfig.selector) {
+        selector = regionConfig.selector;
+        delete regionConfig.selector;
+      }
+  
+      // get the class for the region
+  
+      if (regionIsClass) {
+        RegionClass = regionConfig;
+      }
+  
+      if (!regionIsClass && regionClassIsUndefined) {
+        RegionClass = defaultRegionClass;
+      }
+  
+      if (regionConfig.regionClass) {
+        RegionClass = regionConfig.regionClass;
+        delete regionConfig.regionClass;
+      }
+  
+      if (regionIsString || regionIsClass) {
+        regionConfig = {};
+      }
+  
+      regionConfig.el = selector;
+  
+      // build the region instance
+      var region = new RegionClass(regionConfig);
+  
+      // override the `getEl` function if we have a parentEl
+      // this must be overridden to ensure the selector is found
+      // on the first use of the region. if we try to assign the
+      // region's `el` to `parentEl.find(selector)` in the object
+      // literal to build the region, the element will not be
+      // guaranteed to be in the DOM already, and will cause problems
+      if (regionConfig.parentEl) {
+        region.getEl = function(el) {
+          if (_.isObject(el)) {
+            return Backbone.$(el);
+          }
+          var parentEl = regionConfig.parentEl;
+          if (_.isFunction(parentEl)) {
+            parentEl = parentEl();
+          }
+          return parentEl.find(el);
+        };
+      }
+  
+      return region;
+    }
+  
+  });
+  
+  // Region Instance Methods
+  // -----------------------
+  
+  _.extend(Marionette.Region.prototype, Backbone.Events, {
+  
+    // Displays a backbone view instance inside of the region.
+    // Handles calling the `render` method for you. Reads content
+    // directly from the `el` attribute. Also calls an optional
+    // `onShow` and `onDestroy` method on your view, just after showing
+    // or just before destroying the view, respectively.
+    // The `preventDestroy` option can be used to prevent a view from
+    // the old view being destroyed on show.
+    // The `forceShow` option can be used to force a view to be
+    // re-rendered if it's already shown in the region.
+  
+    show: function(view, options){
+      this._ensureElement();
+  
+      var showOptions = options || {};
+      var isDifferentView = view !== this.currentView;
+      var preventDestroy =  !!showOptions.preventDestroy;
+      var forceShow = !!showOptions.forceShow;
+  
+      // we are only changing the view if there is a view to change to begin with
+      var isChangingView = !!this.currentView;
+  
+      // only destroy the view if we don't want to preventDestroy and the view is different
+      var _shouldDestroyView = !preventDestroy && isDifferentView;
+  
+      if (_shouldDestroyView) {
+        this.empty();
+      }
+  
+      // show the view if the view is different or if you want to re-show the view
+      var _shouldShowView = isDifferentView || forceShow;
+  
+      if (_shouldShowView) {
+        view.render();
+  
+        if (isChangingView) {
+          this.triggerMethod('before:swap', view);
+        }
+  
+        this.triggerMethod('before:show', view);
+        this.triggerMethod.call(view, 'before:show');
+  
+        this.attachHtml(view);
+        this.currentView = view;
+  
+        if (isChangingView) {
+          this.triggerMethod('swap', view);
+        }
+  
+        this.triggerMethod('show', view);
+  
+        if (_.isFunction(view.triggerMethod)) {
+          view.triggerMethod('show');
+        } else {
+          this.triggerMethod.call(view, 'show');
+        }
+  
+        return this;
+      }
+  
+      return this;
+    },
+  
+    _ensureElement: function(){
+      if (!_.isObject(this.el)) {
+        this.$el = this.getEl(this.el);
+        this.el = this.$el[0];
+      }
+  
+      if (!this.$el || this.$el.length === 0) {
+        throwError('An "el" ' + this.$el.selector + ' must exist in DOM');
+      }
+    },
+  
+    // Override this method to change how the region finds the
+    // DOM element that it manages. Return a jQuery selector object.
+    getEl: function(el) {
+      return Backbone.$(el);
+    },
+  
+    // Override this method to change how the new view is
+    // appended to the `$el` that the region is managing
+    attachHtml: function(view) {
+      // empty the node and append new view
+      this.el.innerHTML='';
+      this.el.appendChild(view.el);
+    },
+  
+    // Destroy the current view, if there is one. If there is no
+    // current view, it does nothing and returns immediately.
+    empty: function() {
+      var view = this.currentView;
+      if (!view || view.isDestroyed) { return; }
+  
+      this.triggerMethod('before:empty', view);
+  
+      // call 'destroy' or 'remove', depending on which is found
+      if (view.destroy) { view.destroy(); }
+      else if (view.remove) { view.remove(); }
+  
+      this.triggerMethod('empty', view);
+  
+      delete this.currentView;
+    },
+  
+    // Attach an existing view to the region. This
+    // will not call `render` or `onShow` for the new view,
+    // and will not replace the current HTML for the `el`
+    // of the region.
+    attachView: function(view) {
+      this.currentView = view;
+    },
+  
+    // Reset the region by destroying any existing view and
+    // clearing out the cached `$el`. The next time a view
+    // is shown via this region, the region will re-query the
+    // DOM for the region's `el`.
+    reset: function() {
+      this.empty();
+  
+      if (this.$el) {
+        this.el = this.$el.selector;
+      }
+  
+      delete this.$el;
+    },
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption,
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod
+  });
+  
+  // Copy the `extend` function used by Backbone's classes
+  Marionette.Region.extend = Marionette.extend;
+  
+  // Marionette.RegionManager
+  // ------------------------
+  //
+  // Manage one or more related `Marionette.Region` objects.
+  Marionette.RegionManager = (function(Marionette) {
+  
+    var RegionManager = Marionette.Controller.extend({
+      constructor: function(options) {
+        this._regions = {};
+        Marionette.Controller.call(this, options);
+      },
+  
+      // Add multiple regions using an object literal, where
+      // each key becomes the region name, and each value is
+      // the region definition.
+      addRegions: function(regionDefinitions, defaults) {
+        var regions = {};
+  
+        _.each(regionDefinitions, function(definition, name) {
+          if (_.isString(definition)) {
+            definition = {selector: definition};
+          }
+  
+          if (definition.selector) {
+            definition = _.defaults({}, definition, defaults);
+          }
+  
+          var region = this.addRegion(name, definition);
+          regions[name] = region;
+        }, this);
+  
+        return regions;
+      },
+  
+      // Add an individual region to the region manager,
+      // and return the region instance
+      addRegion: function(name, definition) {
+        var region;
+  
+        var isObject = _.isObject(definition);
+        var isString = _.isString(definition);
+        var hasSelector = !!definition.selector;
+  
+        if (isString || (isObject && hasSelector)) {
+          region = Marionette.Region.buildRegion(definition, Marionette.Region);
+        } else if (_.isFunction(definition)) {
+          region = Marionette.Region.buildRegion(definition, Marionette.Region);
+        } else {
+          region = definition;
+        }
+  
+        this.triggerMethod('before:add:region', name, region);
+  
+        this._store(name, region);
+  
+        this.triggerMethod('add:region', name, region);
+        return region;
+      },
+  
+      // Get a region by name
+      get: function(name) {
+        return this._regions[name];
+      },
+  
+      // Gets all the regions contained within
+      // the `regionManager` instance.
+      getRegions: function(){
+        return _.clone(this._regions);
+      },
+  
+      // Remove a region by name
+      removeRegion: function(name) {
+        var region = this._regions[name];
+        this._remove(name, region);
+      },
+  
+      // Empty all regions in the region manager, and
+      // remove them
+      removeRegions: function() {
+        _.each(this._regions, function(region, name) {
+          this._remove(name, region);
+        }, this);
+      },
+  
+      // Empty all regions in the region manager, but
+      // leave them attached
+      emptyRegions: function() {
+        _.each(this._regions, function(region) {
+          region.empty();
+        }, this);
+      },
+  
+      // Destroy all regions and shut down the region
+      // manager entirely
+      destroy: function() {
+        this.removeRegions();
+        Marionette.Controller.prototype.destroy.apply(this, arguments);
+      },
+  
+      // internal method to store regions
+      _store: function(name, region) {
+        this._regions[name] = region;
+        this._setLength();
+      },
+  
+      // internal method to remove a region
+      _remove: function(name, region) {
+        this.triggerMethod('before:remove:region', name, region);
+        region.empty();
+        region.stopListening();
+        delete this._regions[name];
+        this._setLength();
+        this.triggerMethod('remove:region', name, region);
+      },
+  
+      // set the number of regions current held
+      _setLength: function() {
+        this.length = _.size(this._regions);
+      }
+  
+    });
+  
+    Marionette.actAsCollection(RegionManager.prototype, '_regions');
+  
+    return RegionManager;
+  })(Marionette);
+  
+
+  // Template Cache
+  // --------------
+  
+  // Manage templates stored in `<script>` blocks,
+  // caching them for faster access.
+  Marionette.TemplateCache = function(templateId) {
+    this.templateId = templateId;
+  };
+  
+  // TemplateCache object-level methods. Manage the template
+  // caches from these method calls instead of creating
+  // your own TemplateCache instances
+  _.extend(Marionette.TemplateCache, {
+    templateCaches: {},
+  
+    // Get the specified template by id. Either
+    // retrieves the cached version, or loads it
+    // from the DOM.
+    get: function(templateId) {
+      var cachedTemplate = this.templateCaches[templateId];
+  
+      if (!cachedTemplate) {
+        cachedTemplate = new Marionette.TemplateCache(templateId);
+        this.templateCaches[templateId] = cachedTemplate;
+      }
+  
+      return cachedTemplate.load();
+    },
+  
+    // Clear templates from the cache. If no arguments
+    // are specified, clears all templates:
+    // `clear()`
+    //
+    // If arguments are specified, clears each of the
+    // specified templates from the cache:
+    // `clear("#t1", "#t2", "...")`
+    clear: function() {
+      var i;
+      var args = slice.call(arguments);
+      var length = args.length;
+  
+      if (length > 0) {
+        for (i = 0; i < length; i++) {
+          delete this.templateCaches[args[i]];
+        }
+      } else {
+        this.templateCaches = {};
+      }
+    }
+  });
+  
+  // TemplateCache instance methods, allowing each
+  // template cache object to manage its own state
+  // and know whether or not it has been loaded
+  _.extend(Marionette.TemplateCache.prototype, {
+  
+    // Internal method to load the template
+    load: function() {
+      // Guard clause to prevent loading this template more than once
+      if (this.compiledTemplate) {
+        return this.compiledTemplate;
+      }
+  
+      // Load the template and compile it
+      var template = this.loadTemplate(this.templateId);
+      this.compiledTemplate = this.compileTemplate(template);
+  
+      return this.compiledTemplate;
+    },
+  
+    // Load a template from the DOM, by default. Override
+    // this method to provide your own template retrieval
+    // For asynchronous loading with AMD/RequireJS, consider
+    // using a template-loader plugin as described here:
+    // https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs
+    loadTemplate: function(templateId) {
+      var template = Backbone.$(templateId).html();
+  
+      if (!template || template.length === 0) {
+        throwError('Could not find template: "' + templateId + '"', 'NoTemplateError');
+      }
+  
+      return template;
+    },
+  
+    // Pre-compile the template before caching it. Override
+    // this method if you do not need to pre-compile a template
+    // (JST / RequireJS for example) or if you want to change
+    // the template engine used (Handebars, etc).
+    compileTemplate: function(rawTemplate) {
+      return _.template(rawTemplate);
+    }
+  });
+  
+  // Renderer
+  // --------
+  
+  // Render a template with data by passing in the template
+  // selector and the data to render.
+  Marionette.Renderer = {
+  
+    // Render a template with data. The `template` parameter is
+    // passed to the `TemplateCache` object to retrieve the
+    // template function. Override this method to provide your own
+    // custom rendering and template handling for all of Marionette.
+    render: function(template, data) {
+      if (!template) {
+        throwError('Cannot render the template since its false, null or undefined.',
+          'TemplateNotFoundError');
+      }
+  
+      var templateFunc;
+      if (typeof template === 'function') {
+        templateFunc = template;
+      } else {
+        templateFunc = Marionette.TemplateCache.get(template);
+      }
+  
+      return templateFunc(data);
+    }
+  };
+  
+
+  /* jshint maxlen: 114, nonew: false */
+  // Marionette.View
+  // ---------------
+  
+  // The core view class that other Marionette views extend from.
+  Marionette.View = Backbone.View.extend({
+  
+    constructor: function(options) {
+      _.bindAll(this, 'render');
+  
+      // this exposes view options to the view initializer
+      // this is a backfill since backbone removed the assignment
+      // of this.options
+      // at some point however this may be removed
+      this.options = _.extend({}, _.result(this, 'options'), _.isFunction(options) ? options.call(this) : options);
+      // parses out the @ui DSL for events
+      this.events = this.normalizeUIKeys(_.result(this, 'events'));
+  
+      if (_.isObject(this.behaviors)) {
+        new Marionette.Behaviors(this);
+      }
+  
+      Backbone.View.apply(this, arguments);
+  
+      Marionette.MonitorDOMRefresh(this);
+      this.listenTo(this, 'show', this.onShowCalled);
+    },
+  
+    // Get the template for this view
+    // instance. You can set a `template` attribute in the view
+    // definition or pass a `template: "whatever"` parameter in
+    // to the constructor options.
+    getTemplate: function() {
+      return this.getOption('template');
+    },
+  
+    // Mix in template helper methods. Looks for a
+    // `templateHelpers` attribute, which can either be an
+    // object literal, or a function that returns an object
+    // literal. All methods and attributes from this object
+    // are copies to the object passed in.
+    mixinTemplateHelpers: function(target) {
+      target = target || {};
+      var templateHelpers = this.getOption('templateHelpers');
+      if (_.isFunction(templateHelpers)) {
+        templateHelpers = templateHelpers.call(this);
+      }
+      return _.extend(target, templateHelpers);
+    },
+  
+  
+    normalizeUIKeys: function(hash) {
+      var ui = _.result(this, 'ui');
+      var uiBindings = _.result(this, '_uiBindings');
+      return Marionette.normalizeUIKeys(hash, uiBindings || ui);
+    },
+  
+    // Configure `triggers` to forward DOM events to view
+    // events. `triggers: {"click .foo": "do:foo"}`
+    configureTriggers: function() {
+      if (!this.triggers) { return; }
+  
+      var triggerEvents = {};
+  
+      // Allow `triggers` to be configured as a function
+      var triggers = this.normalizeUIKeys(_.result(this, 'triggers'));
+  
+      // Configure the triggers, prevent default
+      // action and stop propagation of DOM events
+      _.each(triggers, function(value, key) {
+  
+        var hasOptions = _.isObject(value);
+        var eventName = hasOptions ? value.event : value;
+  
+        // build the event handler function for the DOM event
+        triggerEvents[key] = function(e) {
+  
+          // stop the event in its tracks
+          if (e) {
+            var prevent = e.preventDefault;
+            var stop = e.stopPropagation;
+  
+            var shouldPrevent = hasOptions ? value.preventDefault : prevent;
+            var shouldStop = hasOptions ? value.stopPropagation : stop;
+  
+            if (shouldPrevent && prevent) { prevent.apply(e); }
+            if (shouldStop && stop) { stop.apply(e); }
+          }
+  
+          // build the args for the event
+          var args = {
+            view: this,
+            model: this.model,
+            collection: this.collection
+          };
+  
+          // trigger the event
+          this.triggerMethod(eventName, args);
+        };
+  
+      }, this);
+  
+      return triggerEvents;
+    },
+  
+    // Overriding Backbone.View's delegateEvents to handle
+    // the `triggers`, `modelEvents`, and `collectionEvents` configuration
+    delegateEvents: function(events) {
+      this._delegateDOMEvents(events);
+      this.bindEntityEvents(this.model, this.getOption('modelEvents'));
+      this.bindEntityEvents(this.collection, this.getOption('collectionEvents'));
+    },
+  
+    // internal method to delegate DOM events and triggers
+    _delegateDOMEvents: function(events) {
+      events = events || this.events;
+      if (_.isFunction(events)) { events = events.call(this); }
+  
+      // normalize ui keys
+      events = this.normalizeUIKeys(events);
+  
+      var combinedEvents = {};
+  
+      // look up if this view has behavior events
+      var behaviorEvents = _.result(this, 'behaviorEvents') || {};
+      var triggers = this.configureTriggers();
+  
+      // behavior events will be overriden by view events and or triggers
+      _.extend(combinedEvents, behaviorEvents, events, triggers);
+  
+      Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
+    },
+  
+    // Overriding Backbone.View's undelegateEvents to handle unbinding
+    // the `triggers`, `modelEvents`, and `collectionEvents` config
+    undelegateEvents: function() {
+      var args = Array.prototype.slice.call(arguments);
+      Backbone.View.prototype.undelegateEvents.apply(this, args);
+      this.unbindEntityEvents(this.model, this.getOption('modelEvents'));
+      this.unbindEntityEvents(this.collection, this.getOption('collectionEvents'));
+    },
+  
+    // Internal method, handles the `show` event.
+    onShowCalled: function() {},
+  
+    // Internal helper method to verify whether the view hasn't been destroyed
+    _ensureViewIsIntact: function() {
+      if (this.isDestroyed) {
+        var err = new Error('Cannot use a view thats already been destroyed.');
+        err.name = 'ViewDestroyedError';
+        throw err;
+      }
+    },
+  
+    // Default `destroy` implementation, for removing a view from the
+    // DOM and unbinding it. Regions will call this method
+    // for you. You can specify an `onDestroy` method in your view to
+    // add custom code that is called after the view is destroyed.
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      var args = Array.prototype.slice.call(arguments);
+  
+      this.triggerMethod.apply(this, ['before:destroy'].concat(args));
+  
+      // mark as destroyed before doing the actual destroy, to
+      // prevent infinite loops within "destroy" event handlers
+      // that are trying to destroy other views
+      this.isDestroyed = true;
+      this.triggerMethod.apply(this, ['destroy'].concat(args));
+  
+      // unbind UI elements
+      this.unbindUIElements();
+  
+      // remove the view from the DOM
+      this.remove();
+    },
+  
+    // This method binds the elements specified in the "ui" hash inside the view's code with
+    // the associated jQuery selectors.
+    bindUIElements: function() {
+      if (!this.ui) { return; }
+  
+      // store the ui hash in _uiBindings so they can be reset later
+      // and so re-rendering the view will be able to find the bindings
+      if (!this._uiBindings) {
+        this._uiBindings = this.ui;
+      }
+  
+      // get the bindings result, as a function or otherwise
+      var bindings = _.result(this, '_uiBindings');
+  
+      // empty the ui so we don't have anything to start with
+      this.ui = {};
+  
+      // bind each of the selectors
+      _.each(_.keys(bindings), function(key) {
+        var selector = bindings[key];
+        this.ui[key] = this.$(selector);
+      }, this);
+    },
+  
+    // This method unbinds the elements specified in the "ui" hash
+    unbindUIElements: function() {
+      if (!this.ui || !this._uiBindings) { return; }
+  
+      // delete all of the existing ui bindings
+      _.each(this.ui, function($el, name) {
+        delete this.ui[name];
+      }, this);
+  
+      // reset the ui element to the original bindings configuration
+      this.ui = this._uiBindings;
+      delete this._uiBindings;
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod,
+  
+    // Imports the "normalizeMethods" to transform hashes of
+    // events=>function references/names to a hash of events=>function references
+    normalizeMethods: Marionette.normalizeMethods,
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption,
+  
+    // Proxy `unbindEntityEvents` to enable binding view's events from another entity.
+    bindEntityEvents: Marionette.proxyBindEntityEvents,
+  
+    // Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
+    unbindEntityEvents: Marionette.proxyUnbindEntityEvents
+  });
+  
+  // Item View
+  // ---------
+  
+  // A single item view implementation that contains code for rendering
+  // with underscore.js templates, serializing the view's model or collection,
+  // and calling several methods on extended views, such as `onRender`.
+  Marionette.ItemView = Marionette.View.extend({
+  
+    // Setting up the inheritance chain which allows changes to
+    // Marionette.View.prototype.constructor which allows overriding
+    constructor: function() {
+      Marionette.View.apply(this, arguments);
+    },
+  
+    // Serialize the model or collection for the view. If a model is
+    // found, `.toJSON()` is called. If a collection is found, `.toJSON()`
+    // is also called, but is used to populate an `items` array in the
+    // resulting data. If both are found, defaults to the model.
+    // You can override the `serializeData` method in your own view
+    // definition, to provide custom serialization for your view's data.
+    serializeData: function() {
+      var data = {};
+  
+      if (this.model) {
+        data = this.model.toJSON();
+      }
+      else if (this.collection) {
+        data = {items: this.collection.toJSON()};
+      }
+  
+      return data;
+    },
+  
+    // Render the view, defaulting to underscore.js templates.
+    // You can override this in your view definition to provide
+    // a very specific rendering for your view. In general, though,
+    // you should override the `Marionette.Renderer` object to
+    // change how Marionette renders views.
+    render: function() {
+      this._ensureViewIsIntact();
+  
+      this.triggerMethod('before:render', this);
+  
+      var data = this.serializeData();
+      data = this.mixinTemplateHelpers(data);
+  
+      var template = this.getTemplate();
+      var html = Marionette.Renderer.render(template, data);
+      this.attachElContent(html);
+      this.bindUIElements();
+  
+      this.triggerMethod('render', this);
+  
+      return this;
+    },
+  
+    // Attaches the content of a given view.
+    // This method can be overriden to optimize rendering,
+    // or to render in a non standard way.
+    //
+    // For example, using `innerHTML` instead of `$el.html`
+    //
+    // ```js
+    // attachElContent: function(html) {
+    //   this.el.innerHTML = html;
+    //   return this;
+    // }
+    // ```
+    attachElContent: function(html) {
+      this.$el.html(html);
+  
+      return this;
+    },
+  
+    // Override the default destroy event to add a few
+    // more events that are triggered.
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      Marionette.View.prototype.destroy.apply(this, arguments);
+    }
+  });
+  
+  /* jshint maxstatements: 14 */
+  
+  // Collection View
+  // ---------------
+  
+  // A view that iterates over a Backbone.Collection
+  // and renders an individual child view for each model.
+  Marionette.CollectionView = Marionette.View.extend({
+  
+    // used as the prefix for child view events
+    // that are forwarded through the collectionview
+    childViewEventPrefix: 'childview',
+  
+    // constructor
+    // option to pass `{sort: false}` to prevent the `CollectionView` from
+    // maintaining the sorted order of the collection.
+    // This will fallback onto appending childView's to the end.
+    constructor: function(options){
+      var initOptions = options || {};
+      this.sort = _.isUndefined(initOptions.sort) ? true : initOptions.sort;
+  
+      this._initChildViewStorage();
+  
+      Marionette.View.apply(this, arguments);
+  
+      this._initialEvents();
+      this.initRenderBuffer();
+    },
+  
+    // Instead of inserting elements one by one into the page,
+    // it's much more performant to insert elements into a document
+    // fragment and then insert that document fragment into the page
+    initRenderBuffer: function() {
+      this.elBuffer = document.createDocumentFragment();
+      this._bufferedChildren = [];
+    },
+  
+    startBuffering: function() {
+      this.initRenderBuffer();
+      this.isBuffering = true;
+    },
+  
+    endBuffering: function() {
+      this.isBuffering = false;
+      this._triggerBeforeShowBufferedChildren();
+      this.attachBuffer(this, this.elBuffer);
+      this._triggerShowBufferedChildren();
+      this.initRenderBuffer();
+    },
+  
+    _triggerBeforeShowBufferedChildren: function() {
+      if (this._isShown) {
+        _.invoke(this._bufferedChildren, 'triggerMethod', 'before:show');
+      }
+    },
+  
+    _triggerShowBufferedChildren: function() {
+      if (this._isShown) {
+        _.each(this._bufferedChildren, function (child) {
+          if (_.isFunction(child.triggerMethod)) {
+            child.triggerMethod('show');
+          } else {
+            Marionette.triggerMethod.call(child, 'show');
+          }
+        });
+        this._bufferedChildren = [];
+      }
+    },
+  
+    // Configured the initial events that the collection view
+    // binds to.
+    _initialEvents: function() {
+      if (this.collection) {
+        this.listenTo(this.collection, 'add', this._onCollectionAdd);
+        this.listenTo(this.collection, 'remove', this._onCollectionRemove);
+        this.listenTo(this.collection, 'reset', this.render);
+  
+        if (this.sort) {
+          this.listenTo(this.collection, 'sort', this._sortViews);
+        }
+      }
+    },
+  
+    // Handle a child added to the collection
+    _onCollectionAdd: function(child, collection, options) {
+      this.destroyEmptyView();
+      var ChildView = this.getChildView(child);
+      var index = this.collection.indexOf(child);
+      this.addChild(child, ChildView, index);
+    },
+  
+    // get the child view by model it holds, and remove it
+    _onCollectionRemove: function(model) {
+      var view = this.children.findByModel(model);
+      this.removeChildView(view);
+      this.checkEmpty();
+    },
+  
+    // Override from `Marionette.View` to trigger show on child views
+    onShowCalled: function(){
+      this.children.each(function(child){
+        if (_.isFunction(child.triggerMethod)) {
+          child.triggerMethod('show');
+        } else {
+          Marionette.triggerMethod.call(child, 'show');
+        }
+      });
+    },
+  
+    // Render children views. Override this method to
+    // provide your own implementation of a render function for
+    // the collection view.
+    render: function() {
+      this._ensureViewIsIntact();
+      this.triggerMethod('before:render', this);
+      this._renderChildren();
+      this.triggerMethod('render', this);
+      return this;
+    },
+  
+    // Internal method. This checks for any changes in the order of the collection.
+    // If the index of any view doesn't match, it will render.
+    _sortViews: function(){
+      // check for any changes in sort order of views
+      var orderChanged = this.collection.find(function(item, index){
+        var view = this.children.findByModel(item);
+        return view && view._index !== index;
+      }, this);
+  
+      if (orderChanged) {
+        this.render();
+      }
+    },
+  
+    // Internal method. Separated so that CompositeView can have
+    // more control over events being triggered, around the rendering
+    // process
+    _renderChildren: function() {
+      this.startBuffering();
+  
+      this.destroyEmptyView();
+      this.destroyChildren();
+  
+      if (!this.isEmpty(this.collection)) {
+        this.triggerMethod('before:render:collection', this);
+        this.showCollection();
+        this.triggerMethod('render:collection', this);
+      } else {
+        this.showEmptyView();
+      }
+  
+      this.endBuffering();
+    },
+  
+    // Internal method to loop through collection and show each child view.
+    showCollection: function() {
+      var ChildView;
+      this.collection.each(function(child, index) {
+        ChildView = this.getChildView(child);
+        this.addChild(child, ChildView, index);
+      }, this);
+    },
+  
+    // Internal method to show an empty view in place of
+    // a collection of child views, when the collection is empty
+    showEmptyView: function() {
+      var EmptyView = this.getEmptyView();
+  
+      if (EmptyView && !this._showingEmptyView) {
+        this.triggerMethod('before:render:empty');
+  
+        this._showingEmptyView = true;
+        var model = new Backbone.Model();
+        this.addEmptyView(model, EmptyView);
+  
+        this.triggerMethod('render:empty');
+      }
+    },
+  
+    // Internal method to destroy an existing emptyView instance
+    // if one exists. Called when a collection view has been
+    // rendered empty, and then a child is added to the collection.
+    destroyEmptyView: function() {
+      if (this._showingEmptyView) {
+        this.destroyChildren();
+        delete this._showingEmptyView;
+      }
+    },
+  
+    // Retrieve the empty view class
+    getEmptyView: function() {
+      return this.getOption('emptyView');
+    },
+  
+    // Render and show the emptyView. Similar to addChild method
+    // but "child:added" events are not fired, and the event from
+    // emptyView are not forwarded
+    addEmptyView: function(child, EmptyView){
+  
+      // get the emptyViewOptions, falling back to childViewOptions
+      var emptyViewOptions = this.getOption('emptyViewOptions') ||
+                            this.getOption('childViewOptions');
+  
+      if (_.isFunction(emptyViewOptions)){
+        emptyViewOptions = emptyViewOptions.call(this);
+      }
+  
+      // build the empty view
+      var view = this.buildChildView(child, EmptyView, emptyViewOptions);
+  
+      // trigger the 'before:show' event on `view` if the collection view
+      // has already been shown
+      if (this._isShown){
+        this.triggerMethod.call(view, 'before:show');
+      }
+  
+      // Store the `emptyView` like a `childView` so we can properly
+      // remove and/or close it later
+      this.children.add(view);
+  
+      // Render it and show it
+      this.renderChildView(view, -1);
+  
+      // call the 'show' method if the collection view
+      // has already been shown
+      if (this._isShown){
+        this.triggerMethod.call(view, 'show');
+      }
+    },
+  
+    // Retrieve the childView class, either from `this.options.childView`
+    // or from the `childView` in the object definition. The "options"
+    // takes precedence.
+    getChildView: function(child) {
+      var childView = this.getOption('childView');
+  
+      if (!childView) {
+        throwError('A "childView" must be specified', 'NoChildViewError');
+      }
+  
+      return childView;
+    },
+  
+    // Render the child's view and add it to the
+    // HTML for the collection view at a given index.
+    // This will also update the indices of later views in the collection
+    // in order to keep the children in sync with the collection.
+    addChild: function(child, ChildView, index) {
+      var childViewOptions = this.getOption('childViewOptions');
+      if (_.isFunction(childViewOptions)) {
+        childViewOptions = childViewOptions.call(this, child, index);
+      }
+  
+      var view = this.buildChildView(child, ChildView, childViewOptions);
+  
+      // increment indices of views after this one
+      this._updateIndices(view, true, index);
+  
+      this._addChildView(view, index);
+  
+      return view;
+    },
+  
+    // Internal method. This decrements or increments the indices of views after the
+    // added/removed view to keep in sync with the collection.
+    _updateIndices: function(view, increment, index) {
+      if (!this.sort) {
+        return;
+      }
+  
+      if (increment) {
+        // assign the index to the view
+        view._index = index;
+  
+        // increment the index of views after this one
+        this.children.each(function (laterView) {
+          if (laterView._index >= view._index) {
+            laterView._index++;
+          }
+        });
+      }
+      else {
+        // decrement the index of views after this one
+        this.children.each(function (laterView) {
+          if (laterView._index >= view._index) {
+            laterView._index--;
+          }
+        });
+      }
+    },
+  
+  
+    // Internal Method. Add the view to children and render it at
+    // the given index.
+    _addChildView: function(view, index) {
+      // set up the child view event forwarding
+      this.proxyChildEvents(view);
+  
+      this.triggerMethod('before:add:child', view);
+  
+      // Store the child view itself so we can properly
+      // remove and/or destroy it later
+      this.children.add(view);
+      this.renderChildView(view, index);
+  
+      if (this._isShown && !this.isBuffering){
+        if (_.isFunction(view.triggerMethod)) {
+          view.triggerMethod('show');
+        } else {
+          Marionette.triggerMethod.call(view, 'show');
+        }
+      }
+  
+      this.triggerMethod('add:child', view);
+    },
+  
+    // render the child view
+    renderChildView: function(view, index) {
+      view.render();
+      this.attachHtml(this, view, index);
+    },
+  
+    // Build a `childView` for a model in the collection.
+    buildChildView: function(child, ChildViewClass, childViewOptions) {
+      var options = _.extend({model: child}, childViewOptions);
+      return new ChildViewClass(options);
+    },
+  
+    // Remove the child view and destroy it.
+    // This function also updates the indices of
+    // later views in the collection in order to keep
+    // the children in sync with the collection.
+    removeChildView: function(view) {
+  
+      if (view) {
+        this.triggerMethod('before:remove:child', view);
+        // call 'destroy' or 'remove', depending on which is found
+        if (view.destroy) { view.destroy(); }
+        else if (view.remove) { view.remove(); }
+  
+        this.stopListening(view);
+        this.children.remove(view);
+        this.triggerMethod('remove:child', view);
+  
+        // decrement the index of views after this one
+        this._updateIndices(view, false);
+      }
+  
+    },
+  
+    // check if the collection is empty
+    isEmpty: function(collection) {
+      return !this.collection || this.collection.length === 0;
+    },
+  
+    // If empty, show the empty view
+    checkEmpty: function() {
+      if (this.isEmpty(this.collection)) {
+        this.showEmptyView();
+      }
+    },
+  
+    // You might need to override this if you've overridden attachHtml
+    attachBuffer: function(collectionView, buffer) {
+      collectionView.$el.append(buffer);
+    },
+  
+    // Append the HTML to the collection's `el`.
+    // Override this method to do something other
+    // than `.append`.
+    attachHtml: function(collectionView, childView, index) {
+      if (collectionView.isBuffering) {
+        // buffering happens on reset events and initial renders
+        // in order to reduce the number of inserts into the
+        // document, which are expensive.
+        collectionView.elBuffer.appendChild(childView.el);
+        collectionView._bufferedChildren.push(childView);
+      }
+      else {
+        // If we've already rendered the main collection, append
+        // the new child into the correct order if we need to. Otherwise
+        // append to the end.
+        if (!collectionView._insertBefore(childView, index)){
+          collectionView._insertAfter(childView);
+        }
+      }
+    },
+  
+    // Internal method. Check whether we need to insert the view into
+    // the correct position.
+    _insertBefore: function(childView, index) {
+      var currentView;
+      var findPosition = this.sort && (index < this.children.length - 1);
+      if (findPosition) {
+        // Find the view after this one
+        currentView = this.children.find(function (view) {
+          return view._index === index + 1;
+        });
+      }
+  
+      if (currentView) {
+        currentView.$el.before(childView.el);
+        return true;
+      }
+  
+      return false;
+    },
+  
+    // Internal method. Append a view to the end of the $el
+    _insertAfter: function(childView) {
+      this.$el.append(childView.el);
+    },
+  
+    // Internal method to set up the `children` object for
+    // storing all of the child views
+    _initChildViewStorage: function() {
+      this.children = new Backbone.ChildViewContainer();
+    },
+  
+    // Handle cleanup and other destroying needs for the collection of views
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      this.triggerMethod('before:destroy:collection');
+      this.destroyChildren();
+      this.triggerMethod('destroy:collection');
+  
+      Marionette.View.prototype.destroy.apply(this, arguments);
+    },
+  
+    // Destroy the child views that this collection view
+    // is holding on to, if any
+    destroyChildren: function() {
+      this.children.each(this.removeChildView, this);
+      this.checkEmpty();
+    },
+  
+    // Set up the child view event forwarding. Uses a "childview:"
+    // prefix in front of all forwarded events.
+    proxyChildEvents: function(view) {
+      var prefix = this.getOption('childViewEventPrefix');
+  
+      // Forward all child view events through the parent,
+      // prepending "childview:" to the event name
+      this.listenTo(view, 'all', function() {
+        var args = Array.prototype.slice.call(arguments);
+        var rootEvent = args[0];
+        var childEvents = this.normalizeMethods(_.result(this, 'childEvents'));
+  
+        args[0] = prefix + ':' + rootEvent;
+        args.splice(1, 0, view);
+  
+        // call collectionView childEvent if defined
+        if (typeof childEvents !== 'undefined' && _.isFunction(childEvents[rootEvent])) {
+          childEvents[rootEvent].apply(this, args.slice(1));
+        }
+  
+        this.triggerMethod.apply(this, args);
+      }, this);
+    }
+  });
+  
+  /* jshint maxstatements: 17, maxlen: 117 */
+  
+  // Composite View
+  // --------------
+  
+  // Used for rendering a branch-leaf, hierarchical structure.
+  // Extends directly from CollectionView and also renders an
+  // a child view as `modelView`, for the top leaf
+  Marionette.CompositeView = Marionette.CollectionView.extend({
+  
+    // Setting up the inheritance chain which allows changes to
+    // Marionette.CollectionView.prototype.constructor which allows overriding
+    // option to pass '{sort: false}' to prevent the CompositeView from
+    // maintaining the sorted order of the collection.
+    // This will fallback onto appending childView's to the end.
+    constructor: function() {
+      Marionette.CollectionView.apply(this, arguments);
+    },
+  
+    // Configured the initial events that the composite view
+    // binds to. Override this method to prevent the initial
+    // events, or to add your own initial events.
+    _initialEvents: function() {
+  
+      // Bind only after composite view is rendered to avoid adding child views
+      // to nonexistent childViewContainer
+      this.once('render', function() {
+        if (this.collection) {
+          this.listenTo(this.collection, 'add', this._onCollectionAdd);
+          this.listenTo(this.collection, 'remove', this._onCollectionRemove);
+          this.listenTo(this.collection, 'reset', this._renderChildren);
+  
+          if (this.sort) {
+            this.listenTo(this.collection, 'sort', this._sortViews);
+          }
+        }
+      });
+  
+    },
+  
+    // Retrieve the `childView` to be used when rendering each of
+    // the items in the collection. The default is to return
+    // `this.childView` or Marionette.CompositeView if no `childView`
+    // has been defined
+    getChildView: function(child) {
+      var childView = this.getOption('childView') || this.constructor;
+  
+      if (!childView) {
+        throwError('A "childView" must be specified', 'NoChildViewError');
+      }
+  
+      return childView;
+    },
+  
+    // Serialize the collection for the view.
+    // You can override the `serializeData` method in your own view
+    // definition, to provide custom serialization for your view's data.
+    serializeData: function() {
+      var data = {};
+  
+      if (this.model) {
+        data = this.model.toJSON();
+      }
+  
+      return data;
+    },
+  
+    // Renders the model once, and the collection once. Calling
+    // this again will tell the model's view to re-render itself
+    // but the collection will not re-render.
+    render: function() {
+      this._ensureViewIsIntact();
+      this.isRendered = true;
+      this.resetChildViewContainer();
+  
+      this.triggerMethod('before:render', this);
+  
+      this._renderRoot();
+      this._renderChildren();
+  
+      this.triggerMethod('render', this);
+      return this;
+    },
+  
+    _renderChildren: function() {
+      if (this.isRendered) {
+        Marionette.CollectionView.prototype._renderChildren.call(this);
+      }
+    },
+  
+    // Render the root template that the children
+    // views are appended to
+    _renderRoot: function() {
+      var data = {};
+      data = this.serializeData();
+      data = this.mixinTemplateHelpers(data);
+  
+      this.triggerMethod('before:render:template');
+  
+      var template = this.getTemplate();
+      var html = Marionette.Renderer.render(template, data);
+      this.attachElContent(html);
+  
+      // the ui bindings is done here and not at the end of render since they
+      // will not be available until after the model is rendered, but should be
+      // available before the collection is rendered.
+      this.bindUIElements();
+      this.triggerMethod('render:template');
+    },
+  
+    // Attaches the content of the root.
+    // This method can be overriden to optimize rendering,
+    // or to render in a non standard way.
+    //
+    // For example, using `innerHTML` instead of `$el.html`
+    //
+    // ```js
+    // attachElContent: function(html) {
+    //   this.el.innerHTML = html;
+    //   return this;
+    // }
+    // ```
+    attachElContent: function(html) {
+      this.$el.html(html);
+  
+      return this;
+    },
+  
+    // You might need to override this if you've overridden attachHtml
+    attachBuffer: function(compositeView, buffer) {
+      var $container = this.getChildViewContainer(compositeView);
+      $container.append(buffer);
+    },
+  
+    // Internal method. Append a view to the end of the $el.
+    // Overidden from CollectionView to ensure view is appended to
+    // childViewContainer
+    _insertAfter: function (childView) {
+      var $container = this.getChildViewContainer(this);
+      $container.append(childView.el);
+    },
+  
+    // Internal method to ensure an `$childViewContainer` exists, for the
+    // `attachHtml` method to use.
+    getChildViewContainer: function(containerView) {
+      if ('$childViewContainer' in containerView) {
+        return containerView.$childViewContainer;
+      }
+  
+      var container;
+      var childViewContainer = Marionette.getOption(containerView, 'childViewContainer');
+      if (childViewContainer) {
+  
+        var selector = _.isFunction(childViewContainer) ? childViewContainer.call(containerView) : childViewContainer;
+  
+        if (selector.charAt(0) === '@' && containerView.ui) {
+          container = containerView.ui[selector.substr(4)];
+        } else {
+          container = containerView.$(selector);
+        }
+  
+        if (container.length <= 0) {
+          throwError('The specified "childViewContainer" was not found: ' +
+            containerView.childViewContainer, 'ChildViewContainerMissingError');
+        }
+  
+      } else {
+        container = containerView.$el;
+      }
+  
+      containerView.$childViewContainer = container;
+      return container;
+    },
+  
+    // Internal method to reset the `$childViewContainer` on render
+    resetChildViewContainer: function() {
+      if (this.$childViewContainer) {
+        delete this.$childViewContainer;
+      }
+    }
+  });
+  
+  // LayoutView
+  // ----------
+  
+  // Used for managing application layoutViews, nested layoutViews and
+  // multiple regions within an application or sub-application.
+  //
+  // A specialized view class that renders an area of HTML and then
+  // attaches `Region` instances to the specified `regions`.
+  // Used for composite view management and sub-application areas.
+  Marionette.LayoutView = Marionette.ItemView.extend({
+    regionClass: Marionette.Region,
+  
+    // Ensure the regions are available when the `initialize` method
+    // is called.
+    constructor: function(options) {
+      options = options || {};
+  
+      this._firstRender = true;
+      this._initializeRegions(options);
+  
+      Marionette.ItemView.call(this, options);
+    },
+  
+    // LayoutView's render will use the existing region objects the
+    // first time it is called. Subsequent calls will destroy the
+    // views that the regions are showing and then reset the `el`
+    // for the regions to the newly rendered DOM elements.
+    render: function() {
+      this._ensureViewIsIntact();
+  
+      if (this._firstRender) {
+        // if this is the first render, don't do anything to
+        // reset the regions
+        this._firstRender = false;
+      } else {
+        // If this is not the first render call, then we need to
+        // re-initialize the `el` for each region
+        this._reInitializeRegions();
+      }
+  
+      return Marionette.ItemView.prototype.render.apply(this, arguments);
+    },
+  
+    // Handle destroying regions, and then destroy the view itself.
+    destroy: function() {
+      if (this.isDestroyed) { return; }
+  
+      this.regionManager.destroy();
+      Marionette.ItemView.prototype.destroy.apply(this, arguments);
+    },
+  
+    // Add a single region, by name, to the layoutView
+    addRegion: function(name, definition) {
+      this.triggerMethod('before:region:add', name);
+      var regions = {};
+      regions[name] = definition;
+      return this._buildRegions(regions)[name];
+    },
+  
+    // Add multiple regions as a {name: definition, name2: def2} object literal
+    addRegions: function(regions) {
+      this.regions = _.extend({}, this.regions, regions);
+      return this._buildRegions(regions);
+    },
+  
+    // Remove a single region from the LayoutView, by name
+    removeRegion: function(name) {
+      this.triggerMethod('before:region:remove', name);
+      delete this.regions[name];
+      return this.regionManager.removeRegion(name);
+    },
+  
+    // Provides alternative access to regions
+    // Accepts the region name
+    // getRegion('main')
+    getRegion: function(region) {
+      return this.regionManager.get(region);
+    },
+  
+    // Get all regions
+    getRegions: function(){
+      return this.regionManager.getRegions();
+    },
+  
+    // internal method to build regions
+    _buildRegions: function(regions) {
+      var that = this;
+  
+      var defaults = {
+        regionClass: this.getOption('regionClass'),
+        parentEl: function() { return that.$el; }
+      };
+  
+      return this.regionManager.addRegions(regions, defaults);
+    },
+  
+    // Internal method to initialize the regions that have been defined in a
+    // `regions` attribute on this layoutView.
+    _initializeRegions: function(options) {
+      var regions;
+      this._initRegionManager();
+  
+      if (_.isFunction(this.regions)) {
+        regions = this.regions(options);
+      } else {
+        regions = this.regions || {};
+      }
+  
+      // Enable users to define `regions` as instance options.
+      var regionOptions = this.getOption.call(options, 'regions');
+  
+      // enable region options to be a function
+      if (_.isFunction(regionOptions)) {
+        regionOptions = regionOptions.call(this, options);
+      }
+  
+      _.extend(regions, regionOptions);
+  
+      this.addRegions(regions);
+    },
+  
+    // Internal method to re-initialize all of the regions by updating the `el` that
+    // they point to
+    _reInitializeRegions: function() {
+      this.regionManager.emptyRegions();
+      this.regionManager.each(function(region) {
+        region.reset();
+      });
+    },
+  
+    // Enable easy overiding of the default `RegionManager`
+    // for customized region interactions and buisness specific
+    // view logic for better control over single regions.
+    getRegionManager: function() {
+      return new Marionette.RegionManager();
+    },
+  
+    // Internal method to initialize the region manager
+    // and all regions in it
+    _initRegionManager: function() {
+      this.regionManager = this.getRegionManager();
+  
+      this.listenTo(this.regionManager, 'before:add:region', function(name) {
+        this.triggerMethod('before:add:region', name);
+      });
+  
+      this.listenTo(this.regionManager, 'add:region', function(name, region) {
+        this[name] = region;
+        this.triggerMethod('add:region', name, region);
+      });
+  
+      this.listenTo(this.regionManager, 'before:remove:region', function(name) {
+        this.triggerMethod('before:remove:region', name);
+      });
+  
+      this.listenTo(this.regionManager, 'remove:region', function(name, region) {
+        delete this[name];
+        this.triggerMethod('remove:region', name, region);
+      });
+    }
+  });
+  
+
+  // Behavior
+  // -----------
+  
+  // A Behavior is an isolated set of DOM /
+  // user interactions that can be mixed into any View.
+  // Behaviors allow you to blackbox View specific interactions
+  // into portable logical chunks, keeping your views simple and your code DRY.
+  
+  Marionette.Behavior = (function(_, Backbone) {
+    function Behavior(options, view) {
+      // Setup reference to the view.
+      // this comes in handle when a behavior
+      // wants to directly talk up the chain
+      // to the view.
+      this.view = view;
+      this.defaults = _.result(this, 'defaults') || {};
+      this.options  = _.extend({}, this.defaults, options);
+  
+      // proxy behavior $ method to the view
+      // this is useful for doing jquery DOM lookups
+      // scoped to behaviors view.
+      this.$ = function() {
+        return this.view.$.apply(this.view, arguments);
+      };
+  
+      // Call the initialize method passing
+      // the arguments from the instance constructor
+      this.initialize.apply(this, arguments);
+    }
+  
+    _.extend(Behavior.prototype, Backbone.Events, {
+      initialize: function() {},
+  
+      // stopListening to behavior `onListen` events.
+      destroy: function() {
+        this.stopListening();
+      },
+  
+      // import the `triggerMethod` to trigger events with corresponding
+      // methods if the method exists
+      triggerMethod: Marionette.triggerMethod,
+  
+      // Proxy `getOption` to enable getting options from this or this.options by name.
+      getOption: Marionette.proxyGetOption,
+  
+      // Proxy `unbindEntityEvents` to enable binding view's events from another entity.
+      bindEntityEvents: Marionette.proxyBindEntityEvents,
+  
+      // Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.
+      unbindEntityEvents: Marionette.proxyUnbindEntityEvents
+    });
+  
+    // Borrow Backbones extend implementation
+    // this allows us to setup a proper
+    // inheritence pattern that follow in suite
+    // with the rest of Marionette views.
+    Behavior.extend = Marionette.extend;
+  
+    return Behavior;
+  })(_, Backbone);
+  
+  /* jshint maxlen: 143, nonew: false */
+  // Marionette.Behaviors
+  // --------
+  
+  // Behaviors is a utility class that takes care of
+  // glueing your behavior instances to their given View.
+  // The most important part of this class is that you
+  // **MUST** override the class level behaviorsLookup
+  // method for things to work properly.
+  
+  Marionette.Behaviors = (function(Marionette, _) {
+  
+    function Behaviors(view, behaviors) {
+      // Behaviors defined on a view can be a flat object literal
+      // or it can be a function that returns an object.
+      behaviors = Behaviors.parseBehaviors(view, behaviors || _.result(view, 'behaviors'));
+  
+      // Wraps several of the view's methods
+      // calling the methods first on each behavior
+      // and then eventually calling the method on the view.
+      Behaviors.wrap(view, behaviors, [
+        'bindUIElements', 'unbindUIElements',
+        'delegateEvents', 'undelegateEvents',
+        'behaviorEvents', 'triggerMethod',
+        'setElement', 'destroy'
+      ]);
+    }
+  
+    var methods = {
+      setElement: function(setElement, behaviors) {
+        setElement.apply(this, _.tail(arguments, 2));
+  
+        // proxy behavior $el to the view's $el.
+        // This is needed because a view's $el proxy
+        // is not set until after setElement is called.
+        _.each(behaviors, function(b) {
+          b.$el = this.$el;
+        }, this);
+      },
+  
+      destroy: function(destroy, behaviors) {
+        var args = _.tail(arguments, 2);
+        destroy.apply(this, args);
+  
+        // Call destroy on each behavior after
+        // destroying the view.
+        // This unbinds event listeners
+        // that behaviors have registerd for.
+        _.invoke(behaviors, 'destroy', args);
+      },
+  
+      bindUIElements: function(bindUIElements, behaviors) {
+        bindUIElements.apply(this);
+        _.invoke(behaviors, bindUIElements);
+      },
+  
+      unbindUIElements: function(unbindUIElements, behaviors) {
+        unbindUIElements.apply(this);
+        _.invoke(behaviors, unbindUIElements);
+      },
+  
+      triggerMethod: function(triggerMethod, behaviors) {
+        var args = _.tail(arguments, 2);
+        triggerMethod.apply(this, args);
+  
+        _.each(behaviors, function(b) {
+          triggerMethod.apply(b, args);
+        });
+      },
+  
+      delegateEvents: function(delegateEvents, behaviors) {
+        var args = _.tail(arguments, 2);
+        delegateEvents.apply(this, args);
+  
+        _.each(behaviors, function(b) {
+          Marionette.bindEntityEvents(b, this.model, Marionette.getOption(b, 'modelEvents'));
+          Marionette.bindEntityEvents(b, this.collection, Marionette.getOption(b, 'collectionEvents'));
+        }, this);
+      },
+  
+      undelegateEvents: function(undelegateEvents, behaviors) {
+        var args = _.tail(arguments, 2);
+        undelegateEvents.apply(this, args);
+  
+        _.each(behaviors, function(b) {
+          Marionette.unbindEntityEvents(b, this.model, Marionette.getOption(b, 'modelEvents'));
+          Marionette.unbindEntityEvents(b, this.collection, Marionette.getOption(b, 'collectionEvents'));
+        }, this);
+      },
+  
+      behaviorEvents: function(behaviorEvents, behaviors) {
+        var _behaviorsEvents = {};
+        var viewUI = _.result(this, 'ui');
+  
+        _.each(behaviors, function(b, i) {
+          var _events = {};
+          var behaviorEvents = _.clone(_.result(b, 'events')) || {};
+          var behaviorUI = _.result(b, 'ui');
+  
+          // Construct an internal UI hash first using
+          // the views UI hash and then the behaviors UI hash.
+          // This allows the user to use UI hash elements
+          // defined in the parent view as well as those
+          // defined in the given behavior.
+          var ui = _.extend({}, viewUI, behaviorUI);
+  
+          // Normalize behavior events hash to allow
+          // a user to use the @ui. syntax.
+          behaviorEvents = Marionette.normalizeUIKeys(behaviorEvents, ui);
+  
+          _.each(_.keys(behaviorEvents), function(key) {
+            // Append white-space at the end of each key to prevent behavior key collisions.
+            // This is relying on the fact that backbone events considers "click .foo" the same as
+            // "click .foo ".
+  
+            // +2 is used because new Array(1) or 0 is "" and not " "
+            var whitespace = (new Array(i + 2)).join(' ');
+            var eventKey   = key + whitespace;
+            var handler    = _.isFunction(behaviorEvents[key]) ? behaviorEvents[key] : b[behaviorEvents[key]];
+  
+            _events[eventKey] = _.bind(handler, b);
+          });
+  
+          _behaviorsEvents = _.extend(_behaviorsEvents, _events);
+        });
+  
+        return _behaviorsEvents;
+      }
+    };
+  
+    _.extend(Behaviors, {
+  
+      // Placeholder method to be extended by the user.
+      // The method should define the object that stores the behaviors.
+      // i.e.
+      //
+      // ```js
+      // Marionette.Behaviors.behaviorsLookup: function() {
+      //   return App.Behaviors
+      // }
+      // ```
+      behaviorsLookup: function() {
+        throw new Error('You must define where your behaviors are stored.' +
+          'See https://github.com/marionettejs/backbone.marionette' +
+          '/blob/master/docs/marionette.behaviors.md#behaviorslookup');
+      },
+  
+      // Takes care of getting the behavior class
+      // given options and a key.
+      // If a user passes in options.behaviorClass
+      // default to using that. Otherwise delegate
+      // the lookup to the users `behaviorsLookup` implementation.
+      getBehaviorClass: function(options, key) {
+        if (options.behaviorClass) {
+          return options.behaviorClass;
+        }
+  
+        // Get behavior class can be either a flat object or a method
+        return _.isFunction(Behaviors.behaviorsLookup) ? Behaviors.behaviorsLookup.apply(this, arguments)[key] : Behaviors.behaviorsLookup[key];
+      },
+  
+      // Iterate over the behaviors object, for each behavior
+      // instantiate it and get its grouped behaviors.
+      parseBehaviors: function(view, behaviors) {
+        return _.chain(behaviors).map(function(options, key) {
+          var BehaviorClass = Behaviors.getBehaviorClass(options, key);
+  
+          var behavior = new BehaviorClass(options, view);
+          var nestedBehaviors = Behaviors.parseBehaviors(view, _.result(behavior, 'behaviors'));
+  
+          return [behavior].concat(nestedBehaviors);
+        }).flatten().value();
+      },
+  
+      // Wrap view internal methods so that they delegate to behaviors. For example,
+      // `onDestroy` should trigger destroy on all of the behaviors and then destroy itself.
+      // i.e.
+      //
+      // `view.delegateEvents = _.partial(methods.delegateEvents, view.delegateEvents, behaviors);`
+      wrap: function(view, behaviors, methodNames) {
+        _.each(methodNames, function(methodName) {
+          view[methodName] = _.partial(methods[methodName], view[methodName], behaviors);
+        });
+      }
+    });
+  
+    return Behaviors;
+  
+  })(Marionette, _);
+  
+
+  // AppRouter
+  // ---------
+  
+  // Reduce the boilerplate code of handling route events
+  // and then calling a single method on another object.
+  // Have your routers configured to call the method on
+  // your object, directly.
+  //
+  // Configure an AppRouter with `appRoutes`.
+  //
+  // App routers can only take one `controller` object.
+  // It is recommended that you divide your controller
+  // objects in to smaller pieces of related functionality
+  // and have multiple routers / controllers, instead of
+  // just one giant router and controller.
+  //
+  // You can also add standard routes to an AppRouter.
+  
+  Marionette.AppRouter = Backbone.Router.extend({
+  
+    constructor: function(options) {
+      Backbone.Router.apply(this, arguments);
+  
+      this.options = options || {};
+  
+      var appRoutes = this.getOption('appRoutes');
+      var controller = this._getController();
+      this.processAppRoutes(controller, appRoutes);
+      this.on('route', this._processOnRoute, this);
+    },
+  
+    // Similar to route method on a Backbone Router but
+    // method is called on the controller
+    appRoute: function(route, methodName) {
+      var controller = this._getController();
+      this._addAppRoute(controller, route, methodName);
+    },
+  
+    // process the route event and trigger the onRoute
+    // method call, if it exists
+    _processOnRoute: function(routeName, routeArgs) {
+      // find the path that matched
+      var routePath = _.invert(this.appRoutes)[routeName];
+  
+      // make sure an onRoute is there, and call it
+      if (_.isFunction(this.onRoute)) {
+        this.onRoute(routeName, routePath, routeArgs);
+      }
+    },
+  
+    // Internal method to process the `appRoutes` for the
+    // router, and turn them in to routes that trigger the
+    // specified method on the specified `controller`.
+    processAppRoutes: function(controller, appRoutes) {
+      if (!appRoutes) { return; }
+  
+      var routeNames = _.keys(appRoutes).reverse(); // Backbone requires reverted order of routes
+  
+      _.each(routeNames, function(route) {
+        this._addAppRoute(controller, route, appRoutes[route]);
+      }, this);
+    },
+  
+    _getController: function() {
+      return this.getOption('controller');
+    },
+  
+    _addAppRoute: function(controller, route, methodName) {
+      var method = controller[methodName];
+  
+      if (!method) {
+        throwError('Method "' + methodName + '" was not found on the controller');
+      }
+  
+      this.route(route, methodName, _.bind(method, controller));
+    },
+  
+    // Proxy `getOption` to enable getting options from this or this.options by name.
+    getOption: Marionette.proxyGetOption
+  });
+  
+  // Application
+  // -----------
+  
+  // Contain and manage the composite application as a whole.
+  // Stores and starts up `Region` objects, includes an
+  // event aggregator as `app.vent`
+  Marionette.Application = function(options) {
+    this._initRegionManager();
+    this._initCallbacks = new Marionette.Callbacks();
+    var globalCh = Backbone.Wreqr.radio.channel('global');
+    this.vent = globalCh.vent;
+    this.commands = globalCh.commands;
+    this.reqres = globalCh.reqres;
+    this.submodules = {};
+  
+    _.extend(this, options);
+  };
+  
+  _.extend(Marionette.Application.prototype, Backbone.Events, {
+    // Command execution, facilitated by Backbone.Wreqr.Commands
+    execute: function() {
+      this.commands.execute.apply(this.commands, arguments);
+    },
+  
+    // Request/response, facilitated by Backbone.Wreqr.RequestResponse
+    request: function() {
+      return this.reqres.request.apply(this.reqres, arguments);
+    },
+  
+    // Add an initializer that is either run at when the `start`
+    // method is called, or run immediately if added after `start`
+    // has already been called.
+    addInitializer: function(initializer) {
+      this._initCallbacks.add(initializer);
+    },
+  
+    // kick off all of the application's processes.
+    // initializes all of the regions that have been added
+    // to the app, and runs all of the initializer functions
+    start: function(options) {
+      this.triggerMethod('before:start', options);
+      this._initCallbacks.run(options, this);
+      this.triggerMethod('start', options);
+    },
+  
+    // Add regions to your app.
+    // Accepts a hash of named strings or Region objects
+    // addRegions({something: "#someRegion"})
+    // addRegions({something: Region.extend({el: "#someRegion"}) });
+    addRegions: function(regions) {
+      return this._regionManager.addRegions(regions);
+    },
+  
+    // Empty all regions in the app, without removing them
+    emptyRegions: function() {
+      this._regionManager.emptyRegions();
+    },
+  
+    // Removes a region from your app, by name
+    // Accepts the regions name
+    // removeRegion('myRegion')
+    removeRegion: function(region) {
+      this._regionManager.removeRegion(region);
+    },
+  
+    // Provides alternative access to regions
+    // Accepts the region name
+    // getRegion('main')
+    getRegion: function(region) {
+      return this._regionManager.get(region);
+    },
+  
+    // Get all the regions from the region manager
+    getRegions: function(){
+      return this._regionManager.getRegions();
+    },
+  
+    // Create a module, attached to the application
+    module: function(moduleNames, moduleDefinition) {
+  
+      // Overwrite the module class if the user specifies one
+      var ModuleClass = Marionette.Module.getClass(moduleDefinition);
+  
+      // slice the args, and add this application object as the
+      // first argument of the array
+      var args = slice.call(arguments);
+      args.unshift(this);
+  
+      // see the Marionette.Module object for more information
+      return ModuleClass.create.apply(ModuleClass, args);
+    },
+  
+    // Internal method to set up the region manager
+    _initRegionManager: function() {
+      this._regionManager = new Marionette.RegionManager();
+  
+      this.listenTo(this._regionManager, 'before:add:region', function(name) {
+        this.triggerMethod('before:add:region', name);
+      });
+  
+      this.listenTo(this._regionManager, 'add:region', function(name, region) {
+        this[name] = region;
+        this.triggerMethod('add:region', name, region);
+      });
+  
+      this.listenTo(this._regionManager, 'before:remove:region', function(name) {
+        this.triggerMethod('before:remove:region', name);
+      });
+  
+      this.listenTo(this._regionManager, 'remove:region', function(name, region) {
+        delete this[name];
+        this.triggerMethod('remove:region', name, region);
+      });
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod
+  });
+  
+  // Copy the `extend` function used by Backbone's classes
+  Marionette.Application.extend = Marionette.extend;
+  
+  /* jshint maxparams: 9 */
+  
+  // Module
+  // ------
+  
+  // A simple module system, used to create privacy and encapsulation in
+  // Marionette applications
+  Marionette.Module = function(moduleName, app, options) {
+    this.moduleName = moduleName;
+    this.options = _.extend({}, this.options, options);
+    // Allow for a user to overide the initialize
+    // for a given module instance.
+    this.initialize = options.initialize || this.initialize;
+  
+    // Set up an internal store for sub-modules.
+    this.submodules = {};
+  
+    this._setupInitializersAndFinalizers();
+  
+    // Set an internal reference to the app
+    // within a module.
+    this.app = app;
+  
+    // By default modules start with their parents.
+    this.startWithParent = true;
+  
+    if (_.isFunction(this.initialize)) {
+      this.initialize(moduleName, app, this.options);
+    }
+  };
+  
+  Marionette.Module.extend = Marionette.extend;
+  
+  // Extend the Module prototype with events / listenTo, so that the module
+  // can be used as an event aggregator or pub/sub.
+  _.extend(Marionette.Module.prototype, Backbone.Events, {
+  
+    // Initialize is an empty function by default. Override it with your own
+    // initialization logic when extending Marionette.Module.
+    initialize: function() {},
+  
+    // Initializer for a specific module. Initializers are run when the
+    // module's `start` method is called.
+    addInitializer: function(callback) {
+      this._initializerCallbacks.add(callback);
+    },
+  
+    // Finalizers are run when a module is stopped. They are used to teardown
+    // and finalize any variables, references, events and other code that the
+    // module had set up.
+    addFinalizer: function(callback) {
+      this._finalizerCallbacks.add(callback);
+    },
+  
+    // Start the module, and run all of its initializers
+    start: function(options) {
+      // Prevent re-starting a module that is already started
+      if (this._isInitialized) { return; }
+  
+      // start the sub-modules (depth-first hierarchy)
+      _.each(this.submodules, function(mod) {
+        // check to see if we should start the sub-module with this parent
+        if (mod.startWithParent) {
+          mod.start(options);
+        }
+      });
+  
+      // run the callbacks to "start" the current module
+      this.triggerMethod('before:start', options);
+  
+      this._initializerCallbacks.run(options, this);
+      this._isInitialized = true;
+  
+      this.triggerMethod('start', options);
+    },
+  
+    // Stop this module by running its finalizers and then stop all of
+    // the sub-modules for this module
+    stop: function() {
+      // if we are not initialized, don't bother finalizing
+      if (!this._isInitialized) { return; }
+      this._isInitialized = false;
+  
+      this.triggerMethod('before:stop');
+  
+      // stop the sub-modules; depth-first, to make sure the
+      // sub-modules are stopped / finalized before parents
+      _.each(this.submodules, function(mod) { mod.stop(); });
+  
+      // run the finalizers
+      this._finalizerCallbacks.run(undefined, this);
+  
+      // reset the initializers and finalizers
+      this._initializerCallbacks.reset();
+      this._finalizerCallbacks.reset();
+  
+      this.triggerMethod('stop');
+    },
+  
+    // Configure the module with a definition function and any custom args
+    // that are to be passed in to the definition function
+    addDefinition: function(moduleDefinition, customArgs) {
+      this._runModuleDefinition(moduleDefinition, customArgs);
+    },
+  
+    // Internal method: run the module definition function with the correct
+    // arguments
+    _runModuleDefinition: function(definition, customArgs) {
+      // If there is no definition short circut the method.
+      if (!definition) { return; }
+  
+      // build the correct list of arguments for the module definition
+      var args = _.flatten([
+        this,
+        this.app,
+        Backbone,
+        Marionette,
+        Backbone.$, _,
+        customArgs
+      ]);
+  
+      definition.apply(this, args);
+    },
+  
+    // Internal method: set up new copies of initializers and finalizers.
+    // Calling this method will wipe out all existing initializers and
+    // finalizers.
+    _setupInitializersAndFinalizers: function() {
+      this._initializerCallbacks = new Marionette.Callbacks();
+      this._finalizerCallbacks = new Marionette.Callbacks();
+    },
+  
+    // import the `triggerMethod` to trigger events with corresponding
+    // methods if the method exists
+    triggerMethod: Marionette.triggerMethod
+  });
+  
+  // Class methods to create modules
+  _.extend(Marionette.Module, {
+  
+    // Create a module, hanging off the app parameter as the parent object.
+    create: function(app, moduleNames, moduleDefinition) {
+      var module = app;
+  
+      // get the custom args passed in after the module definition and
+      // get rid of the module name and definition function
+      var customArgs = slice.call(arguments);
+      customArgs.splice(0, 3);
+  
+      // Split the module names and get the number of submodules.
+      // i.e. an example module name of `Doge.Wow.Amaze` would
+      // then have the potential for 3 module definitions.
+      moduleNames = moduleNames.split('.');
+      var length = moduleNames.length;
+  
+      // store the module definition for the last module in the chain
+      var moduleDefinitions = [];
+      moduleDefinitions[length - 1] = moduleDefinition;
+  
+      // Loop through all the parts of the module definition
+      _.each(moduleNames, function(moduleName, i) {
+        var parentModule = module;
+        module = this._getModule(parentModule, moduleName, app, moduleDefinition);
+        this._addModuleDefinition(parentModule, module, moduleDefinitions[i], customArgs);
+      }, this);
+  
+      // Return the last module in the definition chain
+      return module;
+    },
+  
+    _getModule: function(parentModule, moduleName, app, def, args) {
+      var options = _.extend({}, def);
+      var ModuleClass = this.getClass(def);
+  
+      // Get an existing module of this name if we have one
+      var module = parentModule[moduleName];
+  
+      if (!module) {
+        // Create a new module if we don't have one
+        module = new ModuleClass(moduleName, app, options);
+        parentModule[moduleName] = module;
+        // store the module on the parent
+        parentModule.submodules[moduleName] = module;
+      }
+  
+      return module;
+    },
+  
+    // ## Module Classes
+    //
+    // Module classes can be used as an alternative to the define pattern.
+    // The extend function of a Module is identical to the extend functions
+    // on other Backbone and Marionette classes.
+    // This allows module lifecyle events like `onStart` and `onStop` to be called directly.
+    getClass: function(moduleDefinition) {
+      var ModuleClass = Marionette.Module;
+  
+      if (!moduleDefinition) {
+        return ModuleClass;
+      }
+  
+      // If all of the module's functionality is defined inside its class,
+      // then the class can be passed in directly. `MyApp.module("Foo", FooModule)`.
+      if (moduleDefinition.prototype instanceof ModuleClass) {
+        return moduleDefinition;
+      }
+  
+      return moduleDefinition.moduleClass || ModuleClass;
+    },
+  
+    // Add the module definition and add a startWithParent initializer function.
+    // This is complicated because module definitions are heavily overloaded
+    // and support an anonymous function, module class, or options object
+    _addModuleDefinition: function(parentModule, module, def, args) {
+      var fn = this._getDefine(def);
+      var startWithParent = this._getStartWithParent(def, module);
+  
+      if (fn) {
+        module.addDefinition(fn, args);
+      }
+  
+      this._addStartWithParent(parentModule, module, startWithParent);
+    },
+  
+    _getStartWithParent: function(def, module) {
+      var swp;
+  
+      if (_.isFunction(def) && (def.prototype instanceof Marionette.Module)) {
+        swp = module.constructor.prototype.startWithParent;
+        return _.isUndefined(swp) ? true : swp;
+      }
+  
+      if (_.isObject(def)) {
+        swp = def.startWithParent;
+        return _.isUndefined(swp) ? true : swp;
+      }
+  
+      return true;
+    },
+  
+    _getDefine: function(def) {
+      if (_.isFunction(def) && !(def.prototype instanceof Marionette.Module)) {
+        return def;
+      }
+  
+      if (_.isObject(def)) {
+        return def.define;
+      }
+  
+      return null;
+    },
+  
+    _addStartWithParent: function(parentModule, module, startWithParent) {
+      module.startWithParent = module.startWithParent && startWithParent;
+  
+      if (!module.startWithParent || !!module.startWithParentIsConfigured) {
+        return;
+      }
+  
+      module.startWithParentIsConfigured = true;
+  
+      parentModule.addInitializer(function(options) {
+        if (module.startWithParent) {
+          module.start(options);
+        }
+      });
+    }
+  });
+  
+
+  return Marionette;
+}));
vendor/assets/javascripts/backbone.marionette.map
@@ -0,0 +1,1 @@
+{"version":3,"file":"lib/backbone.marionette.min.js","sources":["?"],"names":["root","factory","define","amd","Backbone","_","Marionette","exports","require","module","this","throwError","message","name","error","Error","previousChildViewContainer","ChildViewContainer","Container","views","_views","_indexByModel","_indexByCustom","_updateLength","each","add","extend","prototype","view","customIndex","viewCid","cid","model","findByModel","findByModelCid","modelCid","findByCid","findByCustom","index","findByIndex","values","remove","any","key","call","method","apply","tail","arguments","args","isFunction","length","size","methods","concat","toArray","VERSION","noConflict","previousWreqr","Wreqr","Handlers","options","_wreqrHandlers","initialize","Model","Events","setHandlers","handlers","handler","context","isObject","callback","setHandler","config","trigger","hasHandler","getHandler","Array","slice","removeHandler","removeAllHandlers","CommandStorage","_commands","getCommands","commandName","commands","command","instances","addCommand","push","clearCommands","Commands","storageType","constructor","_initializeStorage","on","_executeCommands","execute","storage","StorageType","RequestResponse","request","EventAggregator","EA","Channel","channelName","vent","reqres","reset","off","stopListening","connectEvents","hash","_connect","connectCommands","connectRequests","type","fn","eventName","bind","radio","Radio","_channels","_proxyMethods","channel","_getChannel","system","messageSystems","proxyMethod","messageSystem","previousMarionette","Deferred","$","getOption","target","optionName","value","undefined","proxyGetOption","normalizeMethods","normalizedHash","normalizeUIKeys","ui","keys","v","pattern","match","replace","r","actAsCollection","object","listProperty","list","result","triggerMethod","getEventName","prefix","toUpperCase","splitter","event","methodName","MonitorDOMRefresh","documentElement","handleShow","_isShown","triggerDOMRefresh","handleRender","_isRendered","isInDOM","contains","el","listenTo","document","bindFromStrings","entity","evt","methodNames","split","bindToFunction","unbindFromStrings","unbindToFunction","iterateEvents","bindings","functionCallback","stringCallback","bindEntityEvents","unbindEntityEvents","proxyBindEntityEvents","proxyUnbindEntityEvents","Callbacks","_deferred","_callbacks","contextOverride","promise","cb","ctx","then","run","resolve","callbacks","Controller","destroy","Region","$el","getEl","buildRegion","regionConfig","defaultRegionClass","regionIsString","isString","regionSelectorIsString","selector","regionClassIsUndefined","isUndefined","regionClass","regionIsClass","RegionClass","region","parentEl","find","show","_ensureElement","showOptions","isDifferentView","currentView","preventDestroy","forceShow","isChangingView","_shouldDestroyView","empty","_shouldShowView","render","attachHtml","innerHTML","appendChild","isDestroyed","attachView","RegionManager","_regions","addRegions","regionDefinitions","defaults","regions","definition","addRegion","hasSelector","_store","get","getRegions","clone","removeRegion","_remove","removeRegions","emptyRegions","_setLength","TemplateCache","templateId","templateCaches","cachedTemplate","load","clear","i","compiledTemplate","template","loadTemplate","compileTemplate","html","rawTemplate","Renderer","data","templateFunc","View","bindAll","events","behaviors","Behaviors","onShowCalled","getTemplate","mixinTemplateHelpers","templateHelpers","uiBindings","configureTriggers","triggers","triggerEvents","hasOptions","e","prevent","preventDefault","stop","stopPropagation","shouldPrevent","shouldStop","collection","delegateEvents","_delegateDOMEvents","combinedEvents","behaviorEvents","undelegateEvents","_ensureViewIsIntact","err","unbindUIElements","bindUIElements","_uiBindings","ItemView","serializeData","toJSON","items","attachElContent","CollectionView","childViewEventPrefix","initOptions","sort","_initChildViewStorage","_initialEvents","initRenderBuffer","elBuffer","createDocumentFragment","_bufferedChildren","startBuffering","isBuffering","endBuffering","_triggerBeforeShowBufferedChildren","attachBuffer","_triggerShowBufferedChildren","invoke","child","_onCollectionAdd","_onCollectionRemove","_sortViews","destroyEmptyView","ChildView","getChildView","indexOf","addChild","children","removeChildView","checkEmpty","_renderChildren","orderChanged","item","_index","destroyChildren","isEmpty","showEmptyView","showCollection","EmptyView","getEmptyView","_showingEmptyView","addEmptyView","emptyViewOptions","buildChildView","renderChildView","childView","childViewOptions","_updateIndices","_addChildView","increment","laterView","proxyChildEvents","ChildViewClass","collectionView","buffer","append","_insertBefore","_insertAfter","findPosition","before","rootEvent","childEvents","splice","CompositeView","once","isRendered","resetChildViewContainer","_renderRoot","compositeView","$container","getChildViewContainer","containerView","$childViewContainer","container","childViewContainer","charAt","substr","LayoutView","_firstRender","_initializeRegions","_reInitializeRegions","regionManager","_buildRegions","getRegion","that","_initRegionManager","regionOptions","getRegionManager","Behavior","parseBehaviors","wrap","setElement","b","_behaviorsEvents","viewUI","_events","behaviorUI","whitespace","join","eventKey","behaviorsLookup","getBehaviorClass","behaviorClass","chain","map","BehaviorClass","behavior","nestedBehaviors","flatten","partial","AppRouter","Router","appRoutes","controller","_getController","processAppRoutes","_processOnRoute","appRoute","route","_addAppRoute","routeName","routeArgs","routePath","invert","onRoute","routeNames","reverse","Application","_initCallbacks","globalCh","submodules","addInitializer","initializer","start","_regionManager","moduleNames","moduleDefinition","ModuleClass","Module","getClass","unshift","create","moduleName","app","_setupInitializersAndFinalizers","startWithParent","_initializerCallbacks","addFinalizer","_finalizerCallbacks","_isInitialized","mod","addDefinition","customArgs","_runModuleDefinition","moduleDefinitions","parentModule","_getModule","_addModuleDefinition","def","moduleClass","_getDefine","_getStartWithParent","_addStartWithParent","swp","startWithParentIsConfigured"],"mappings":"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"}
\ No newline at end of file
vendor/assets/javascripts/backbone.wreqr.js
@@ -0,0 +1,440 @@
+// Backbone.Wreqr (Backbone.Marionette)
+// ----------------------------------
+// v1.3.1
+//
+// Copyright (c)2014 Derick Bailey, Muted Solutions, LLC.
+// Distributed under MIT license
+//
+// http://github.com/marionettejs/backbone.wreqr
+
+
+(function(root, factory) {
+
+  if (typeof define === 'function' && define.amd) {
+    define(['backbone', 'underscore'], function(Backbone, _) {
+      return factory(Backbone, _);
+    });
+  } else if (typeof exports !== 'undefined') {
+    var Backbone = require('backbone');
+    var _ = require('underscore');
+    module.exports = factory(Backbone, _);
+  } else {
+    factory(root.Backbone, root._);
+  }
+
+}(this, function(Backbone, _) {
+  "use strict";
+
+  var previousWreqr = Backbone.Wreqr;
+
+  var Wreqr = Backbone.Wreqr = {};
+
+  Backbone.Wreqr.VERSION = '1.3.1';
+
+  Backbone.Wreqr.noConflict = function () {
+    Backbone.Wreqr = previousWreqr;
+    return this;
+  };
+
+  // Handlers
+  // --------
+  // A registry of functions to call, given a name
+  
+  Wreqr.Handlers = (function(Backbone, _){
+    "use strict";
+    
+    // Constructor
+    // -----------
+  
+    var Handlers = function(options){
+      this.options = options;
+      this._wreqrHandlers = {};
+      
+      if (_.isFunction(this.initialize)){
+        this.initialize(options);
+      }
+    };
+  
+    Handlers.extend = Backbone.Model.extend;
+  
+    // Instance Members
+    // ----------------
+  
+    _.extend(Handlers.prototype, Backbone.Events, {
+  
+      // Add multiple handlers using an object literal configuration
+      setHandlers: function(handlers){
+        _.each(handlers, function(handler, name){
+          var context = null;
+  
+          if (_.isObject(handler) && !_.isFunction(handler)){
+            context = handler.context;
+            handler = handler.callback;
+          }
+  
+          this.setHandler(name, handler, context);
+        }, this);
+      },
+  
+      // Add a handler for the given name, with an
+      // optional context to run the handler within
+      setHandler: function(name, handler, context){
+        var config = {
+          callback: handler,
+          context: context
+        };
+  
+        this._wreqrHandlers[name] = config;
+  
+        this.trigger("handler:add", name, handler, context);
+      },
+  
+      // Determine whether or not a handler is registered
+      hasHandler: function(name){
+        return !! this._wreqrHandlers[name];
+      },
+  
+      // Get the currently registered handler for
+      // the specified name. Throws an exception if
+      // no handler is found.
+      getHandler: function(name){
+        var config = this._wreqrHandlers[name];
+  
+        if (!config){
+          return;
+        }
+  
+        return function(){
+          var args = Array.prototype.slice.apply(arguments);
+          return config.callback.apply(config.context, args);
+        };
+      },
+  
+      // Remove a handler for the specified name
+      removeHandler: function(name){
+        delete this._wreqrHandlers[name];
+      },
+  
+      // Remove all handlers from this registry
+      removeAllHandlers: function(){
+        this._wreqrHandlers = {};
+      }
+    });
+  
+    return Handlers;
+  })(Backbone, _);
+  
+  // Wreqr.CommandStorage
+  // --------------------
+  //
+  // Store and retrieve commands for execution.
+  Wreqr.CommandStorage = (function(){
+    "use strict";
+  
+    // Constructor function
+    var CommandStorage = function(options){
+      this.options = options;
+      this._commands = {};
+  
+      if (_.isFunction(this.initialize)){
+        this.initialize(options);
+      }
+    };
+  
+    // Instance methods
+    _.extend(CommandStorage.prototype, Backbone.Events, {
+  
+      // Get an object literal by command name, that contains
+      // the `commandName` and the `instances` of all commands
+      // represented as an array of arguments to process
+      getCommands: function(commandName){
+        var commands = this._commands[commandName];
+  
+        // we don't have it, so add it
+        if (!commands){
+  
+          // build the configuration
+          commands = {
+            command: commandName, 
+            instances: []
+          };
+  
+          // store it
+          this._commands[commandName] = commands;
+        }
+  
+        return commands;
+      },
+  
+      // Add a command by name, to the storage and store the
+      // args for the command
+      addCommand: function(commandName, args){
+        var command = this.getCommands(commandName);
+        command.instances.push(args);
+      },
+  
+      // Clear all commands for the given `commandName`
+      clearCommands: function(commandName){
+        var command = this.getCommands(commandName);
+        command.instances = [];
+      }
+    });
+  
+    return CommandStorage;
+  })();
+  
+  // Wreqr.Commands
+  // --------------
+  //
+  // A simple command pattern implementation. Register a command
+  // handler and execute it.
+  Wreqr.Commands = (function(Wreqr){
+    "use strict";
+  
+    return Wreqr.Handlers.extend({
+      // default storage type
+      storageType: Wreqr.CommandStorage,
+  
+      constructor: function(options){
+        this.options = options || {};
+  
+        this._initializeStorage(this.options);
+        this.on("handler:add", this._executeCommands, this);
+  
+        var args = Array.prototype.slice.call(arguments);
+        Wreqr.Handlers.prototype.constructor.apply(this, args);
+      },
+  
+      // Execute a named command with the supplied args
+      execute: function(name, args){
+        name = arguments[0];
+        args = Array.prototype.slice.call(arguments, 1);
+  
+        if (this.hasHandler(name)){
+          this.getHandler(name).apply(this, args);
+        } else {
+          this.storage.addCommand(name, args);
+        }
+  
+      },
+  
+      // Internal method to handle bulk execution of stored commands
+      _executeCommands: function(name, handler, context){
+        var command = this.storage.getCommands(name);
+  
+        // loop through and execute all the stored command instances
+        _.each(command.instances, function(args){
+          handler.apply(context, args);
+        });
+  
+        this.storage.clearCommands(name);
+      },
+  
+      // Internal method to initialize storage either from the type's
+      // `storageType` or the instance `options.storageType`.
+      _initializeStorage: function(options){
+        var storage;
+  
+        var StorageType = options.storageType || this.storageType;
+        if (_.isFunction(StorageType)){
+          storage = new StorageType();
+        } else {
+          storage = StorageType;
+        }
+  
+        this.storage = storage;
+      }
+    });
+  
+  })(Wreqr);
+  
+  // Wreqr.RequestResponse
+  // ---------------------
+  //
+  // A simple request/response implementation. Register a
+  // request handler, and return a response from it
+  Wreqr.RequestResponse = (function(Wreqr){
+    "use strict";
+  
+    return Wreqr.Handlers.extend({
+      request: function(){
+        var name = arguments[0];
+        var args = Array.prototype.slice.call(arguments, 1);
+        if (this.hasHandler(name)) {
+          return this.getHandler(name).apply(this, args);
+        }
+      }
+    });
+  
+  })(Wreqr);
+  
+  // Event Aggregator
+  // ----------------
+  // A pub-sub object that can be used to decouple various parts
+  // of an application through event-driven architecture.
+  
+  Wreqr.EventAggregator = (function(Backbone, _){
+    "use strict";
+    var EA = function(){};
+  
+    // Copy the `extend` function used by Backbone's classes
+    EA.extend = Backbone.Model.extend;
+  
+    // Copy the basic Backbone.Events on to the event aggregator
+    _.extend(EA.prototype, Backbone.Events);
+  
+    return EA;
+  })(Backbone, _);
+  
+  // Wreqr.Channel
+  // --------------
+  //
+  // An object that wraps the three messaging systems:
+  // EventAggregator, RequestResponse, Commands
+  Wreqr.Channel = (function(Wreqr){
+    "use strict";
+  
+    var Channel = function(channelName) {
+      this.vent        = new Backbone.Wreqr.EventAggregator();
+      this.reqres      = new Backbone.Wreqr.RequestResponse();
+      this.commands    = new Backbone.Wreqr.Commands();
+      this.channelName = channelName;
+    };
+  
+    _.extend(Channel.prototype, {
+  
+      // Remove all handlers from the messaging systems of this channel
+      reset: function() {
+        this.vent.off();
+        this.vent.stopListening();
+        this.reqres.removeAllHandlers();
+        this.commands.removeAllHandlers();
+        return this;
+      },
+  
+      // Connect a hash of events; one for each messaging system
+      connectEvents: function(hash, context) {
+        this._connect('vent', hash, context);
+        return this;
+      },
+  
+      connectCommands: function(hash, context) {
+        this._connect('commands', hash, context);
+        return this;
+      },
+  
+      connectRequests: function(hash, context) {
+        this._connect('reqres', hash, context);
+        return this;
+      },
+  
+      // Attach the handlers to a given message system `type`
+      _connect: function(type, hash, context) {
+        if (!hash) {
+          return;
+        }
+  
+        context = context || this;
+        var method = (type === 'vent') ? 'on' : 'setHandler';
+  
+        _.each(hash, function(fn, eventName) {
+          this[type][method](eventName, _.bind(fn, context));
+        }, this);
+      }
+    });
+  
+  
+    return Channel;
+  })(Wreqr);
+  
+  // Wreqr.Radio
+  // --------------
+  //
+  // An object that lets you communicate with many channels.
+  Wreqr.radio = (function(Wreqr){
+    "use strict";
+  
+    var Radio = function() {
+      this._channels = {};
+      this.vent = {};
+      this.commands = {};
+      this.reqres = {};
+      this._proxyMethods();
+    };
+  
+    _.extend(Radio.prototype, {
+  
+      channel: function(channelName) {
+        if (!channelName) {
+          throw new Error('Channel must receive a name');
+        }
+  
+        return this._getChannel( channelName );
+      },
+  
+      _getChannel: function(channelName) {
+        var channel = this._channels[channelName];
+  
+        if(!channel) {
+          channel = new Wreqr.Channel(channelName);
+          this._channels[channelName] = channel;
+        }
+  
+        return channel;
+      },
+  
+      _proxyMethods: function() {
+        _.each(['vent', 'commands', 'reqres'], function(system) {
+          _.each( messageSystems[system], function(method) {
+            this[system][method] = proxyMethod(this, system, method);
+          }, this);
+        }, this);
+      }
+    });
+  
+  
+    var messageSystems = {
+      vent: [
+        'on',
+        'off',
+        'trigger',
+        'once',
+        'stopListening',
+        'listenTo',
+        'listenToOnce'
+      ],
+  
+      commands: [
+        'execute',
+        'setHandler',
+        'setHandlers',
+        'removeHandler',
+        'removeAllHandlers'
+      ],
+  
+      reqres: [
+        'request',
+        'setHandler',
+        'setHandlers',
+        'removeHandler',
+        'removeAllHandlers'
+      ]
+    };
+  
+    var proxyMethod = function(radio, system, method) {
+      return function(channelName) {
+        var messageSystem = radio._getChannel(channelName)[system];
+        var args = Array.prototype.slice.call(arguments, 1);
+  
+        return messageSystem[method].apply(messageSystem, args);
+      };
+    };
+  
+    return new Radio();
+  
+  })(Wreqr);
+  
+
+  return Backbone.Wreqr;
+
+}));
vendor/assets/javascripts/json2.js
@@ -0,0 +1,489 @@
+/*
+    json2.js
+    2014-02-04
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+*/
+
+/*jslint evil: true, regexp: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (typeof JSON !== 'object') {
+    JSON = {};
+}
+
+(function () {
+    'use strict';
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function () {
+
+            return isFinite(this.valueOf())
+                ? this.getUTCFullYear()     + '-' +
+                    f(this.getUTCMonth() + 1) + '-' +
+                    f(this.getUTCDate())      + 'T' +
+                    f(this.getUTCHours())     + ':' +
+                    f(this.getUTCMinutes())   + ':' +
+                    f(this.getUTCSeconds())   + 'Z'
+                : null;
+        };
+
+        String.prototype.toJSON      =
+            Number.prototype.toJSON  =
+            Boolean.prototype.toJSON = function () {
+                return this.valueOf();
+            };
+    }
+
+    var cx,
+        escapable,
+        gap,
+        indent,
+        meta,
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
+            var c = meta[a];
+            return typeof c === 'string'
+                ? c
+                : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+        }) + '"' : '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0
+                    ? '[]'
+                    : gap
+                    ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+                    : '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    if (typeof rep[i] === 'string') {
+                        k = rep[i];
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.prototype.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0
+                ? '{}'
+                : gap
+                ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+                : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        };
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                    typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.prototype.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            text = String(text);
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/
+                    .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
+                        .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
+                        .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function'
+                    ? walk({'': j}, '')
+                    : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
vendor/assets/javascripts/underscore.js
@@ -31,6 +31,15 @@
   // All **ECMAScript 5** native function implementations that we hope to use
   // are declared here.
   var
+    nativeForEach      = ArrayProto.forEach,
+    nativeMap          = ArrayProto.map,
+    nativeReduce       = ArrayProto.reduce,
+    nativeReduceRight  = ArrayProto.reduceRight,
+    nativeFilter       = ArrayProto.filter,
+    nativeEvery        = ArrayProto.every,
+    nativeSome         = ArrayProto.some,
+    nativeIndexOf      = ArrayProto.indexOf,
+    nativeLastIndexOf  = ArrayProto.lastIndexOf,
     nativeIsArray      = Array.isArray,
     nativeKeys         = Object.keys,
     nativeBind         = FuncProto.bind;
@@ -58,66 +67,37 @@
   // Current version.
   _.VERSION = '1.6.0';
 
-  // Internal function: creates a callback bound to its context if supplied
-  var createCallback = 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);
-    };
-  };
-
-  // An internal function to generate lookup iterators.
-  var lookupIterator = function(value, context, argCount) {
-    if (value == null) return _.identity;
-    if (_.isFunction(value)) return createCallback(value, context, argCount);
-    if (_.isObject(value)) return _.matches(value);
-    return _.property(value);
-  };
-
   // Collection Functions
   // --------------------
 
   // The cornerstone, an `each` implementation, aka `forEach`.
-  // Handles raw objects in addition to array-likes. Treats all
-  // sparse array-likes as if they were dense.
-  _.each = _.forEach = function(obj, iterator, context) {
-    var i, length;
+  // 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;
-    iterator = createCallback(iterator, context);
-    if (obj.length === +obj.length) {
-      for (i = 0, length = obj.length; i < length; i++) {
-        if (iterator(obj[i], i, obj) === breaker) break;
+    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;
       }
     } else {
       var keys = _.keys(obj);
-      for (i = 0, length = keys.length; i < length; i++) {
-        if (iterator(obj[keys[i]], keys[i], obj) === breaker) break;
+      for (var i = 0, length = keys.length; i < length; i++) {
+        if (iterator.call(context, obj[keys[i]], keys[i], obj) === breaker) return;
       }
     }
     return obj;
   };
 
   // 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;
-    iterator = lookupIterator(iterator, context);
-    _.each(obj, function(value, index, list) {
-      results.push(iterator(value, index, list));
+    if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
+    each(obj, function(value, index, list) {
+      results.push(iterator.call(context, value, index, list));
     });
     return results;
   };
@@ -125,52 +105,58 @@
   var reduceError = 'Reduce of empty array with no initial value';
 
   // **Reduce** builds up a single result from a list of values, aka `inject`,
-  // or `foldl`.
+  // 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 = [];
-    iterator = createCallback(iterator, context, 4);
-    _.each(obj, function(value, index, list) {
+    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(memo, value, index, list);
+        memo = iterator.call(context, memo, value, index, list);
       }
     });
-    if (!initial) throw TypeError(reduceError);
+    if (!initial) throw new TypeError(reduceError);
     return memo;
   };
 
   // The right-associative version of reduce, also known as `foldr`.
+  // Delegates to **ECMAScript 5**'s native `reduceRight` if available.
   _.reduceRight = _.foldr = function(obj, iterator, memo, context) {
     var initial = arguments.length > 2;
     if (obj == null) obj = [];
+    if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
+      if (context) iterator = _.bind(iterator, context);
+      return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);
+    }
     var length = obj.length;
-    iterator = createCallback(iterator, context, 4);
     if (length !== +length) {
       var keys = _.keys(obj);
       length = keys.length;
     }
-    _.each(obj, function(value, index, list) {
+    each(obj, function(value, index, list) {
       index = keys ? keys[--length] : --length;
       if (!initial) {
         memo = obj[index];
         initial = true;
       } else {
-        memo = iterator(memo, obj[index], index, list);
+        memo = iterator.call(context, memo, obj[index], index, list);
       }
     });
-    if (!initial) throw TypeError(reduceError);
+    if (!initial) throw new TypeError(reduceError);
     return memo;
   };
 
   // Return the first value which passes a truth test. Aliased as `detect`.
   _.find = _.detect = function(obj, predicate, context) {
     var result;
-    predicate = lookupIterator(predicate, context);
-    _.some(obj, function(value, index, list) {
-      if (predicate(value, index, list)) {
+    any(obj, function(value, index, list) {
+      if (predicate.call(context, value, index, list)) {
         result = value;
         return true;
       }
@@ -179,44 +165,49 @@
   };
 
   // Return all the elements that pass a truth test.
+  // Delegates to **ECMAScript 5**'s native `filter` if available.
   // Aliased as `select`.
   _.filter = _.select = function(obj, predicate, context) {
     var results = [];
     if (obj == null) return results;
-    predicate = lookupIterator(predicate, context);
-    _.each(obj, function(value, index, list) {
-      if (predicate(value, index, list)) results.push(value);
+    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);
     });
     return results;
   };
 
   // Return all the elements for which a truth test fails.
   _.reject = function(obj, predicate, context) {
-    return _.filter(obj, _.negate(lookupIterator(predicate)), context);
+    return _.filter(obj, function(value, index, list) {
+      return !predicate.call(context, value, index, list);
+    }, context);
   };
 
   // Determine whether all of the elements match a truth test.
+  // Delegates to **ECMAScript 5**'s native `every` if available.
   // Aliased as `all`.
   _.every = _.all = function(obj, predicate, context) {
+    predicate || (predicate = _.identity);
     var result = true;
     if (obj == null) return result;
-    predicate = lookupIterator(predicate, context);
-    _.each(obj, function(value, index, list) {
-      result = predicate(value, index, list);
-      if (!result) return breaker;
+    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;
   };
 
   // Determine if at least one element in the object matches a truth test.
+  // Delegates to **ECMAScript 5**'s native `some` if available.
   // Aliased as `any`.
-  _.some = _.any = function(obj, predicate, context) {
+  var any = _.some = _.any = function(obj, predicate, context) {
+    predicate || (predicate = _.identity);
     var result = false;
     if (obj == null) return result;
-    predicate = lookupIterator(predicate, context);
-    _.each(obj, function(value, index, list) {
-      result = predicate(value, index, list);
-      if (result) return breaker;
+    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;
   };
@@ -225,8 +216,10 @@
   // Aliased as `include`.
   _.contains = _.include = function(obj, target) {
     if (obj == null) return false;
-    if (obj.length !== +obj.length) obj = _.values(obj);
-    return _.indexOf(obj, target) >= 0;
+    if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
+    return any(obj, function(value) {
+      return value === target;
+    });
   };
 
   // Invoke a method (with arguments) on every item in a collection.
@@ -255,51 +248,37 @@
     return _.find(obj, _.matches(attrs));
   };
 
-  // Return the maximum element (or element-based computation).
+  // 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) {
-    var result = -Infinity, lastComputed = -Infinity,
-        value, computed;
-    if (!iterator && _.isArray(obj)) {
-      for (var i = 0, length = obj.length; i < length; i++) {
-        value = obj[i];
-        if (value > result) {
-          result = value;
-        }
-      }
-    } else {
-      iterator = lookupIterator(iterator, context);
-      _.each(obj, function(value, index, list) {
-        computed = iterator(value, index, list);
-        if (computed > lastComputed || computed === -Infinity && result === -Infinity) {
-          result = value;
-          lastComputed = computed;
-        }
-      });
+    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
+      return Math.max.apply(Math, obj);
     }
+    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;
+      }
+    });
     return result;
   };
 
   // Return the minimum element (or element-based computation).
   _.min = function(obj, iterator, context) {
-    var result = Infinity, lastComputed = Infinity,
-        value, computed;
-    if (!iterator && _.isArray(obj)) {
-      for (var i = 0, length = obj.length; i < length; i++) {
-        value = obj[i];
-        if (value < result) {
-          result = value;
-        }
-      }
-    } else {
-      iterator = lookupIterator(iterator, context);
-      _.each(obj, function(value, index, list) {
-        computed = iterator(value, index, list);
-        if (computed < lastComputed || computed === Infinity && result === Infinity) {
-          result = value;
-          lastComputed = computed;
-        }
-      });
+    if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {
+      return Math.min.apply(Math, obj);
     }
+    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;
+      }
+    });
     return result;
   };
 
@@ -309,7 +288,7 @@
     var rand;
     var index = 0;
     var shuffled = [];
-    _.each(obj, function(value) {
+    each(obj, function(value) {
       rand = _.random(index++);
       shuffled[index - 1] = shuffled[rand];
       shuffled[rand] = value;
@@ -328,14 +307,21 @@
     return _.shuffle(obj).slice(0, Math.max(0, n));
   };
 
+  // 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, context);
+    iterator = lookupIterator(iterator);
     return _.pluck(_.map(obj, function(value, index, list) {
       return {
         value: value,
         index: index,
-        criteria: iterator(value, index, list)
+        criteria: iterator.call(context, value, index, list)
       };
     }).sort(function(left, right) {
       var a = left.criteria;
@@ -352,10 +338,10 @@
   var group = function(behavior) {
     return function(obj, iterator, context) {
       var result = {};
-      iterator = lookupIterator(iterator, context);
-      _.each(obj, function(value, index) {
-        var key = iterator(value, index, obj);
-        behavior(result, value, key);
+      iterator = lookupIterator(iterator);
+      each(obj, function(value, index) {
+        var key = iterator.call(context, value, index, obj);
+        behavior(result, key, value);
       });
       return result;
     };
@@ -363,32 +349,32 @@
 
   // Groups the object's values by a criterion. Pass either a string attribute
   // to group by, or a function that returns the criterion.
-  _.groupBy = group(function(result, value, key) {
-    if (_.has(result, key)) result[key].push(value); else result[key] = [value];
+  _.groupBy = group(function(result, key, value) {
+    _.has(result, key) ? result[key].push(value) : result[key] = [value];
   });
 
   // Indexes the object's values by a criterion, similar to `groupBy`, but for
   // when you know that your index values will be unique.
-  _.indexBy = group(function(result, value, key) {
+  _.indexBy = group(function(result, key, value) {
     result[key] = value;
   });
 
   // Counts instances of an object that group by a certain criterion. Pass
   // either a string attribute to count by, or a function that returns the
   // criterion.
-  _.countBy = group(function(result, value, key) {
-    if (_.has(result, key)) result[key]++; else result[key] = 1;
+  _.countBy = group(function(result, key) {
+    _.has(result, key) ? result[key]++ : result[key] = 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, iterator, context) {
-    iterator = lookupIterator(iterator, context, 1);
-    var value = iterator(obj);
+    iterator = lookupIterator(iterator);
+    var value = iterator.call(context, obj);
     var low = 0, high = array.length;
     while (low < high) {
       var mid = (low + high) >>> 1;
-      if (iterator(array[mid]) < value) low = mid + 1; else high = mid;
+      iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;
     }
     return low;
   };
@@ -404,18 +390,7 @@
   // Return the number of elements in an object.
   _.size = function(obj) {
     if (obj == null) return 0;
-    return obj.length === +obj.length ? obj.length : _.keys(obj).length;
-  };
-
-  // 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 = lookupIterator(predicate, context);
-    var pass = [], fail = [];
-    _.each(obj, function(value, key, obj) {
-      (predicate(value, key, obj) ? pass : fail).push(value);
-    });
-    return [pass, fail];
+    return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;
   };
 
   // Array Functions
@@ -426,7 +401,7 @@
   // allows it to work with `_.map`.
   _.first = _.head = _.take = function(array, n, guard) {
     if (array == null) return void 0;
-    if (n == null || guard) return array[0];
+    if ((n == null) || guard) return array[0];
     if (n < 0) return [];
     return slice.call(array, 0, n);
   };
@@ -436,14 +411,14 @@
   // the array, excluding the last N. The **guard** check allows it to work with
   // `_.map`.
   _.initial = function(array, n, guard) {
-    return slice.call(array, 0, Math.max(0, array.length - (n == null || guard ? 1 : n)));
+    return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));
   };
 
   // Get the last element of an array. Passing **n** will return the last N
   // values in the array. The **guard** check allows it to work with `_.map`.
   _.last = function(array, n, guard) {
     if (array == null) return void 0;
-    if (n == null || guard) return array[array.length - 1];
+    if ((n == null) || guard) return array[array.length - 1];
     return slice.call(array, Math.max(array.length - n, 0));
   };
 
@@ -452,7 +427,7 @@
   // the rest N values in the array. The **guard**
   // check allows it to work with `_.map`.
   _.rest = _.tail = _.drop = function(array, n, guard) {
-    return slice.call(array, n == null || guard ? 1 : n);
+    return slice.call(array, (n == null) || guard ? 1 : n);
   };
 
   // Trim out all falsy values from an array.
@@ -461,26 +436,23 @@
   };
 
   // Internal implementation of a recursive `flatten` function.
-  var flatten = function(input, shallow, strict, output) {
+  var flatten = function(input, shallow, output) {
     if (shallow && _.every(input, _.isArray)) {
       return concat.apply(output, input);
     }
-    for (var i = 0, length = input.length; i < length; i++) {
-      var value = input[i];
-      if (!_.isArray(value) && !_.isArguments(value)) {
-        if (!strict) output.push(value);
-      } else if (shallow) {
-        push.apply(output, value);
+    each(input, function(value) {
+      if (_.isArray(value) || _.isArguments(value)) {
+        shallow ? push.apply(output, value) : flatten(value, shallow, output);
       } else {
-        flatten(value, shallow, strict, output);
+        output.push(value);
       }
-    }
+    });
     return output;
   };
 
   // Flatten out an array, either recursively (by default), or just one level.
   _.flatten = function(array, shallow) {
-    return flatten(array, shallow, false, []);
+    return flatten(array, shallow, []);
   };
 
   // Return a version of the array that does not contain the specified value(s).
@@ -488,71 +460,68 @@
     return _.difference(array, slice.call(arguments, 1));
   };
 
+  // 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];
+  };
+
   // Produce a duplicate-free version of the array. If the array has already
   // been sorted, you have the option of using a faster algorithm.
   // Aliased as `unique`.
   _.uniq = _.unique = function(array, isSorted, iterator, context) {
-    if (array == null) return [];
     if (_.isFunction(isSorted)) {
       context = iterator;
       iterator = isSorted;
       isSorted = false;
     }
-    if (iterator) iterator = lookupIterator(iterator, context);
-    var result = [];
+    var initial = iterator ? _.map(array, iterator, context) : array;
+    var results = [];
     var seen = [];
-    for (var i = 0, length = array.length; i < length; i++) {
-      var value = array[i];
-      if (iterator) value = iterator(value, i, array);
-      if (isSorted ? !i || seen !== value : !_.contains(seen, value)) {
-        if (isSorted) seen = value;
-        else seen.push(value);
-        result.push(array[i]);
+    each(initial, function(value, index) {
+      if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {
+        seen.push(value);
+        results.push(array[index]);
       }
-    }
-    return result;
+    });
+    return results;
   };
 
   // Produce an array that contains the union: each distinct element from all of
   // the passed-in arrays.
   _.union = function() {
-    return _.uniq(flatten(arguments, true, true, []));
+    return _.uniq(_.flatten(arguments, true));
   };
 
   // Produce an array that contains every item shared between all the
   // passed-in arrays.
   _.intersection = function(array) {
-    if (array == null) return [];
-    var result = [];
-    var argsLength = arguments.length;
-    for (var i = 0, length = array.length; 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;
+    var rest = slice.call(arguments, 1);
+    return _.filter(_.uniq(array), function(item) {
+      return _.every(rest, function(other) {
+        return _.contains(other, item);
+      });
+    });
   };
 
   // Take the difference between one array and a number of other arrays.
   // Only the elements present in just the first array will remain.
   _.difference = function(array) {
-    var rest = flatten(slice.call(arguments, 1), true, true, []);
-    return _.filter(array, function(value){
-      return !_.contains(rest, value);
-    });
+    var rest = concat.apply(ArrayProto, slice.call(arguments, 1));
+    return _.filter(array, function(value){ return !_.contains(rest, value); });
   };
 
   // Zip together multiple lists into a single array -- elements that share
   // an index go together.
-  _.zip = function(array) {
-    if (array == null) return [];
-    var length = _.max(arguments, 'length').length;
-    var results = Array(length);
+  _.zip = function() {
+    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);
+      results[i] = _.pluck(arguments, '' + i);
     }
     return results;
   };
@@ -573,8 +542,10 @@
     return result;
   };
 
-  // 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 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) {
@@ -582,23 +553,26 @@
     var i = 0, length = array.length;
     if (isSorted) {
       if (typeof isSorted == 'number') {
-        i = isSorted < 0 ? Math.max(0, length + isSorted) : isSorted;
+        i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);
       } else {
         i = _.sortedIndex(array, item);
         return array[i] === item ? i : -1;
       }
     }
+    if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);
     for (; i < length; i++) if (array[i] === item) return i;
     return -1;
   };
 
+  // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
   _.lastIndexOf = function(array, item, from) {
     if (array == null) return -1;
-    var idx = array.length;
-    if (typeof from == 'number') {
-      idx = from < 0 ? idx + from + 1 : Math.min(idx, from + 1);
+    var hasIndex = from != null;
+    if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {
+      return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);
     }
-    while (--idx >= 0) if (array[idx] === item) return idx;
+    var i = (hasIndex ? from : array.length);
+    while (i--) if (array[i] === item) return i;
     return -1;
   };
 
@@ -614,9 +588,9 @@
 
     var length = Math.max(Math.ceil((stop - start) / step), 0);
     var idx = 0;
-    var range = Array(length);
+    var range = new Array(length);
 
-    while (idx < length) {
+    while(idx < length) {
       range[idx++] = start;
       start += step;
     }
@@ -628,7 +602,7 @@
   // ------------------
 
   // Reusable constructor function for prototype setting.
-  var Ctor = function(){};
+  var ctor = function(){};
 
   // Create a function bound to a given object (assigning `this`, and arguments,
   // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if
@@ -636,18 +610,17 @@
   _.bind = function(func, context) {
     var args, bound;
     if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));
-    if (!_.isFunction(func)) throw TypeError('Bind must be called on a function');
+    if (!_.isFunction(func)) throw new TypeError;
     args = slice.call(arguments, 2);
-    bound = function() {
+    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;
+      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;
     };
-    return bound;
   };
 
   // Partially apply a function by creating a version that has had some of its
@@ -670,34 +643,27 @@
   // are the method names to be bound. Useful for ensuring that all callbacks
   // defined on an object belong to it.
   _.bindAll = function(obj) {
-    var i = 1, length = arguments.length, key;
-    if (length <= 1) throw Error('bindAll must be passed function names');
-    for (; i < length; i++) {
-      key = arguments[i];
-      obj[key] = _.bind(obj[key], obj);
-    }
+    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); });
     return obj;
   };
 
   // Memoize an expensive function by storing its results.
   _.memoize = function(func, hasher) {
-    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[key];
+    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));
     };
-    memoize.cache = {};
-    return memoize;
   };
 
   // Delays a function for the given number of milliseconds, and then calls
   // it with the arguments supplied.
   _.delay = function(func, wait) {
     var args = slice.call(arguments, 2);
-    return setTimeout(function(){
-      return func.apply(null, args);
-    }, wait);
+    return setTimeout(function(){ return func.apply(null, args); }, wait);
   };
 
   // Defers a function, scheduling it to run after the current call stack has
@@ -715,12 +681,12 @@
     var context, args, result;
     var timeout = null;
     var previous = 0;
-    if (!options) options = {};
+    options || (options = {});
     var later = function() {
       previous = options.leading === false ? 0 : _.now();
       timeout = null;
       result = func.apply(context, args);
-      if (!timeout) context = args = null;
+      context = args = null;
     };
     return function() {
       var now = _.now();
@@ -728,12 +694,12 @@
       var remaining = wait - (now - previous);
       context = this;
       args = arguments;
-      if (remaining <= 0 || remaining > wait) {
+      if (remaining <= 0) {
         clearTimeout(timeout);
         timeout = null;
         previous = now;
         result = func.apply(context, args);
-        if (!timeout) context = args = null;
+        context = args = null;
       } else if (!timeout && options.trailing !== false) {
         timeout = setTimeout(later, remaining);
       }
@@ -750,14 +716,13 @@
 
     var later = function() {
       var last = _.now() - timestamp;
-
-      if (last < wait && last > 0) {
+      if (last < wait) {
         timeout = setTimeout(later, wait - last);
       } else {
         timeout = null;
         if (!immediate) {
           result = func.apply(context, args);
-          if (!timeout) context = args = null;
+          context = args = null;
         }
       }
     };
@@ -767,7 +732,9 @@
       args = arguments;
       timestamp = _.now();
       var callNow = immediate && !timeout;
-      if (!timeout) timeout = setTimeout(later, wait);
+      if (!timeout) {
+        timeout = setTimeout(later, wait);
+      }
       if (callNow) {
         result = func.apply(context, args);
         context = args = null;
@@ -797,23 +764,16 @@
     return _.partial(wrapper, func);
   };
 
-  // Returns a negated version of the passed-in predicate.
-  _.negate = function(predicate) {
-    return function() {
-      return !predicate.apply(this, arguments);
-    };
-  };
-
   // Returns a function that is the composition of a list of functions, each
   // consuming the return value of the function that follows.
   _.compose = function() {
-    var args = arguments;
-    var start = args.length - 1;
+    var funcs = arguments;
     return function() {
-      var i = start;
-      var result = args[start].apply(this, arguments);
-      while (i--) result = args[i].call(this, result);
-      return result;
+      var args = arguments;
+      for (var i = funcs.length - 1; i >= 0; i--) {
+        args = [funcs[i].apply(this, args)];
+      }
+      return args[0];
     };
   };
 
@@ -843,7 +803,7 @@
   _.values = function(obj) {
     var keys = _.keys(obj);
     var length = keys.length;
-    var values = Array(length);
+    var values = new Array(length);
     for (var i = 0; i < length; i++) {
       values[i] = obj[keys[i]];
     }
@@ -854,7 +814,7 @@
   _.pairs = function(obj) {
     var keys = _.keys(obj);
     var length = keys.length;
-    var pairs = Array(length);
+    var pairs = new Array(length);
     for (var i = 0; i < length; i++) {
       pairs[i] = [keys[i], obj[keys[i]]];
     }
@@ -883,60 +843,45 @@
 
   // Extend a given object with all the properties in passed-in object(s).
   _.extend = function(obj) {
-    if (!_.isObject(obj)) return obj;
-    var source, prop;
-    for (var i = 1, length = arguments.length; i < length; i++) {
-      source = arguments[i];
-      for (prop in source) {
-        obj[prop] = source[prop];
+    each(slice.call(arguments, 1), function(source) {
+      if (source) {
+        for (var prop in source) {
+          obj[prop] = source[prop];
+        }
       }
-    }
+    });
     return obj;
   };
 
   // Return a copy of the object only containing the whitelisted properties.
-  _.pick = function(obj, iterator, context) {
-    var result = {}, key;
-    if (obj == null) return result;
-    if (_.isFunction(iterator)) {
-      iterator = createCallback(iterator, context);
-      for (key in obj) {
-        var value = obj[key];
-        if (iterator(value, key, obj)) result[key] = value;
-      }
-    } else {
-      var keys = concat.apply([], slice.call(arguments, 1));
-      obj = Object(obj);
-      for (var i = 0, length = keys.length; i < length; i++) {
-        key = keys[i];
-        if (key in obj) result[key] = obj[key];
-      }
-    }
-    return result;
+  _.pick = function(obj) {
+    var copy = {};
+    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
+    each(keys, function(key) {
+      if (key in obj) copy[key] = obj[key];
+    });
+    return copy;
   };
 
    // Return a copy of the object without the blacklisted properties.
-  _.omit = function(obj, iterator, context) {
-    if (_.isFunction(iterator)) {
-      iterator = _.negate(iterator);
-    } else {
-      var keys = _.map(concat.apply([], slice.call(arguments, 1)), String);
-      iterator = function(value, key) {
-        return !_.contains(keys, key);
-      };
+  _.omit = function(obj) {
+    var copy = {};
+    var keys = concat.apply(ArrayProto, slice.call(arguments, 1));
+    for (var key in obj) {
+      if (!_.contains(keys, key)) copy[key] = obj[key];
     }
-    return _.pick(obj, iterator, context);
+    return copy;
   };
 
   // Fill in a given object with default properties.
   _.defaults = function(obj) {
-    if (!_.isObject(obj)) return obj;
-    for (var i = 1, length = arguments.length; i < length; i++) {
-      var source = arguments[i];
-      for (var prop in source) {
-        if (obj[prop] === void 0) obj[prop] = source[prop];
+    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;
   };
 
@@ -958,7 +903,7 @@
   var eq = function(a, b, aStack, bStack) {
     // Identical objects are equal. `0 === -0`, but they aren't identical.
     // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).
-    if (a === b) return a !== 0 || 1 / a === 1 / b;
+    if (a === b) return a !== 0 || 1 / a == 1 / b;
     // A strict comparison is necessary because `null == undefined`.
     if (a == null || b == null) return a === b;
     // Unwrap any wrapped objects.
@@ -966,27 +911,29 @@
     if (b instanceof _) b = b._wrapped;
     // Compare `[[Class]]` names.
     var className = toString.call(a);
-    if (className !== toString.call(b)) return false;
+    if (className != toString.call(b)) return false;
     switch (className) {
-      // 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')
+      // Strings, numbers, dates, and booleans are compared by value.
       case '[object String]':
         // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
         // equivalent to `new String("5")`.
-        return '' + a === '' + b;
+        return a == String(b);
       case '[object Number]':
-        // `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;
+        // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for
+        // other numeric values.
+        return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);
       case '[object Date]':
       case '[object Boolean]':
         // Coerce dates and booleans to numeric primitive values. Dates are compared by their
         // millisecond representations. Note that invalid dates with millisecond representations
         // of `NaN` are not equivalent.
-        return +a === +b;
+        return +a == +b;
+      // RegExps are compared by their source patterns and flags.
+      case '[object RegExp]':
+        return a.source == b.source &&
+               a.global == b.global &&
+               a.multiline == b.multiline &&
+               a.ignoreCase == b.ignoreCase;
     }
     if (typeof a != 'object' || typeof b != 'object') return false;
     // Assume equality for cyclic structures. The algorithm for detecting cyclic
@@ -995,29 +942,25 @@
     while (length--) {
       // Linear search. Performance is inversely proportional to the number of
       // unique nested structures.
-      if (aStack[length] === a) return bStack[length] === b;
+      if (aStack[length] == a) return bStack[length] == b;
     }
     // Objects with different constructors are not equivalent, but `Object`s
     // from different frames are.
     var aCtor = a.constructor, bCtor = b.constructor;
-    if (
-      aCtor !== bCtor &&
-      // Handle Object.create(x) cases
-      'constructor' in a && 'constructor' in b &&
-      !(_.isFunction(aCtor) && aCtor instanceof aCtor &&
-        _.isFunction(bCtor) && bCtor instanceof bCtor)
-    ) {
+    if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&
+                             _.isFunction(bCtor) && (bCtor instanceof bCtor))
+                        && ('constructor' in a && 'constructor' in b)) {
       return false;
     }
     // Add the first object to the stack of traversed objects.
     aStack.push(a);
     bStack.push(b);
-    var size, result;
+    var size = 0, result = true;
     // Recursively compare objects and arrays.
-    if (className === '[object Array]') {
+    if (className == '[object Array]') {
       // Compare array lengths to determine if a deep comparison is necessary.
       size = a.length;
-      result = size === b.length;
+      result = size == b.length;
       if (result) {
         // Deep compare the contents, ignoring non-numeric properties.
         while (size--) {
@@ -1026,17 +969,21 @@
       }
     } else {
       // Deep compare objects.
-      var keys = _.keys(a), key;
-      size = keys.length;
-      // Ensure that both objects contain the same number of properties before comparing deep equality.
-      result = _.keys(b).length == size;
-      if (result) {
-        while (size--) {
-          // Deep compare each member
-          key = keys[size];
+      for (var key in a) {
+        if (_.has(a, key)) {
+          // Count the expected number of properties.
+          size++;
+          // Deep compare each member.
           if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;
         }
       }
+      // Ensure that both objects contain the same number of properties.
+      if (result) {
+        for (key in b) {
+          if (_.has(b, key) && !(size--)) break;
+        }
+        result = !size;
+      }
     }
     // Remove the first object from the stack of traversed objects.
     aStack.pop();
@@ -1053,7 +1000,7 @@
   // An "empty" object has no enumerable own-properties.
   _.isEmpty = function(obj) {
     if (obj == null) return true;
-    if (_.isArray(obj) || _.isString(obj) || _.isArguments(obj)) return obj.length === 0;
+    if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
     for (var key in obj) if (_.has(obj, key)) return false;
     return true;
   };
@@ -1066,7 +1013,7 @@
   // Is a given value an array?
   // Delegates to ECMA5's native Array.isArray
   _.isArray = nativeIsArray || function(obj) {
-    return toString.call(obj) === '[object Array]';
+    return toString.call(obj) == '[object Array]';
   };
 
   // Is a given variable an object?
@@ -1075,9 +1022,9 @@
   };
 
   // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.
-  _.each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
+  each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {
     _['is' + name] = function(obj) {
-      return toString.call(obj) === '[object ' + name + ']';
+      return toString.call(obj) == '[object ' + name + ']';
     };
   });
 
@@ -1085,12 +1032,12 @@
   // there isn't any inspectable "Arguments" type.
   if (!_.isArguments(arguments)) {
     _.isArguments = function(obj) {
-      return _.has(obj, 'callee');
+      return !!(obj && _.has(obj, 'callee'));
     };
   }
 
   // Optimize `isFunction` if appropriate.
-  if (typeof /./ !== 'function') {
+  if (typeof (/./) !== 'function') {
     _.isFunction = function(obj) {
       return typeof obj === 'function';
     };
@@ -1103,12 +1050,12 @@
 
   // Is the given value `NaN`? (NaN is the only number which does not equal itself).
   _.isNaN = function(obj) {
-    return _.isNumber(obj) && obj !== +obj;
+    return _.isNumber(obj) && obj != +obj;
   };
 
   // Is a given value a boolean?
   _.isBoolean = function(obj) {
-    return obj === true || obj === false || toString.call(obj) === '[object Boolean]';
+    return obj === true || obj === false || toString.call(obj) == '[object Boolean]';
   };
 
   // Is a given value equal to null?
@@ -1124,7 +1071,7 @@
   // Shortcut function for checking if an object has a given property directly
   // on itself (in other words, not on a prototype).
   _.has = function(obj, key) {
-    return obj != null && hasOwnProperty.call(obj, key);
+    return hasOwnProperty.call(obj, key);
   };
 
   // Utility Functions
@@ -1143,13 +1090,11 @@
   };
 
   _.constant = function(value) {
-    return function() {
+    return function () {
       return value;
     };
   };
 
-  _.noop = function(){};
-
   _.property = function(key) {
     return function(obj) {
       return obj[key];
@@ -1159,18 +1104,19 @@
   // Returns a predicate for checking whether an object has a given set of `key:value` pairs.
   _.matches = function(attrs) {
     return function(obj) {
-      if (obj == null) return _.isEmpty(attrs);
-      if (obj === attrs) return true;
-      for (var key in attrs) if (attrs[key] !== obj[key]) return false;
+      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;
-    };
+    }
   };
 
   // Run a function **n** times.
   _.times = function(n, iterator, context) {
     var accum = Array(Math.max(0, n));
-    iterator = createCallback(iterator, context, 1);
-    for (var i = 0; i < n; i++) accum[i] = iterator(i);
+    for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);
     return accum;
   };
 
@@ -1184,9 +1130,7 @@
   };
 
   // A (possibly faster) way to get the current timestamp as an integer.
-  _.now = Date.now || function() {
-    return new Date().getTime();
-  };
+  _.now = Date.now || function() { return new Date().getTime(); };
 
   // List of HTML entities for escaping.
   var entityMap = {
@@ -1202,8 +1146,8 @@
 
   // Regexes containing the keys and values listed immediately above.
   var entityRegexes = {
-    escape:   RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
-    unescape: RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
+    escape:   new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),
+    unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')
   };
 
   // Functions for escaping and unescaping strings to/from HTML interpolation.
@@ -1221,7 +1165,19 @@
   _.result = function(object, property) {
     if (object == null) return void 0;
     var value = object[property];
-    return _.isFunction(value) ? object[property]() : value;
+    return _.isFunction(value) ? value.call(object) : value;
+  };
+
+  // Add your own custom functions to the Underscore object.
+  _.mixin = function(obj) {
+    each(_.functions(obj), function(name) {
+      var func = _[name] = obj[name];
+      _.prototype[name] = function() {
+        var args = [this._wrapped];
+        push.apply(args, arguments);
+        return result.call(this, func.apply(_, args));
+      };
+    });
   };
 
   // Generate a unique integer id (unique within the entire client session).
@@ -1252,24 +1208,22 @@
     '\\':     '\\',
     '\r':     'r',
     '\n':     'n',
+    '\t':     't',
     '\u2028': 'u2028',
     '\u2029': 'u2029'
   };
 
-  var escaper = /\\|'|\r|\n|\u2028|\u2029/g;
-
-  var escapeChar = function(match) {
-    return '\\' + escapes[match];
-  };
+  var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
 
   // JavaScript micro-templating, similar to John Resig's implementation.
   // Underscore templating handles arbitrary delimiters, preserves whitespace,
   // and correctly escapes quotes within interpolated code.
   _.template = function(text, data, settings) {
+    var render;
     settings = _.defaults({}, settings, _.templateSettings);
 
     // Combine delimiters into one regular expression via alternation.
-    var matcher = RegExp([
+    var matcher = new RegExp([
       (settings.escape || noMatch).source,
       (settings.interpolate || noMatch).source,
       (settings.evaluate || noMatch).source
@@ -1279,18 +1233,19 @@
     var index = 0;
     var source = "__p+='";
     text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
-      source += text.slice(index, offset).replace(escaper, escapeChar);
-      index = offset + match.length;
+      source += text.slice(index, offset)
+        .replace(escaper, function(match) { return '\\' + escapes[match]; });
 
       if (escape) {
         source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
-      } else if (interpolate) {
+      }
+      if (interpolate) {
         source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
-      } else if (evaluate) {
+      }
+      if (evaluate) {
         source += "';\n" + evaluate + "\n__p+='";
       }
-
-      // Adobe VMs need the match returned to produce the correct offest.
+      index = offset + match.length;
       return match;
     });
     source += "';\n";
@@ -1300,10 +1255,10 @@
 
     source = "var __t,__p='',__j=Array.prototype.join," +
       "print=function(){__p+=__j.call(arguments,'');};\n" +
-      source + 'return __p;\n';
+      source + "return __p;\n";
 
     try {
-      var render = Function(settings.variable || 'obj', '_', source);
+      render = new Function(settings.variable || 'obj', '_', source);
     } catch (e) {
       e.source = source;
       throw e;
@@ -1314,18 +1269,15 @@
       return render.call(this, data, _);
     };
 
-    // Provide the compiled source as a convenience for precompilation.
-    var argument = settings.variable || 'obj';
-    template.source = 'function(' + argument + '){\n' + source + '}';
+    // Provide the compiled function source as a convenience for precompilation.
+    template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
 
     return template;
   };
 
-  // Add a "chain" function. Start chaining a wrapped Underscore object.
+  // Add a "chain" function, which will delegate to the wrapper.
   _.chain = function(obj) {
-    var instance = _(obj);
-    instance._chain = true;
-    return instance;
+    return _(obj).chain();
   };
 
   // OOP
@@ -1339,44 +1291,42 @@
     return this._chain ? _(obj).chain() : obj;
   };
 
-  // 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));
-      };
-    });
-  };
-
   // Add all of the Underscore functions to the wrapper object.
   _.mixin(_);
 
   // Add all mutator Array functions to the wrapper.
-  _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
+  each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
     var method = ArrayProto[name];
     _.prototype[name] = function() {
       var obj = this._wrapped;
       method.apply(obj, arguments);
-      if ((name === 'shift' || name === 'splice') && obj.length === 0) delete obj[0];
+      if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];
       return result.call(this, obj);
     };
   });
 
   // Add all accessor Array functions to the wrapper.
-  _.each(['concat', 'join', 'slice'], function(name) {
+  each(['concat', 'join', 'slice'], function(name) {
     var method = ArrayProto[name];
     _.prototype[name] = function() {
       return result.call(this, method.apply(this._wrapped, arguments));
     };
   });
 
-  // Extracts the result from a wrapped and chained object.
-  _.prototype.value = function() {
-    return this._wrapped;
-  };
+  _.extend(_.prototype, {
+
+    // Start chaining a wrapped Underscore object.
+    chain: function() {
+      this._chain = true;
+      return this;
+    },
+
+    // Extracts the result from a wrapped and chained object.
+    value: function() {
+      return this._wrapped;
+    }
+
+  });
 
   // AMD registration happens at the end for compatibility with AMD loaders
   // that may not enforce next-turn semantics on modules. Even though general
@@ -1390,4 +1340,4 @@
       return _;
     });
   }
-}.call(this));
+}).call(this);
Gemfile
@@ -36,7 +36,6 @@ gem 'exifr'
 gem 'aws-sdk'
 gem 'mime-types'
 gem 'ejs'
-gem 'marionette-rails'
 gem 'js-routes'
 
 group :development do
Gemfile.lock
@@ -177,8 +177,6 @@ GEM
     mail (2.5.4)
       mime-types (~> 1.16)
       treetop (~> 1.4.8)
-    marionette-rails (2.0.0)
-      railties (>= 3.1)
     memoizable (0.4.2)
       thread_safe (~> 0.3, >= 0.3.1)
     mime-types (1.25.1)
@@ -355,7 +353,6 @@ DEPENDENCIES
   js-routes
   kaminari (~> 0.15.0)
   lol_dba
-  marionette-rails
   mime-types
   mini_magick
   newrelic_rpm