(function(/*! Brunch !*/) {
  'use strict';

  var globals = typeof window !== 'undefined' ? window : global;
  if (typeof globals.require === 'function') return;

  var modules = {};
  var cache = {};

  var has = function(object, name) {
    return ({}).hasOwnProperty.call(object, name);
  };

  var expand = function(root, name) {
    var results = [], parts, part;
    if (/^\.\.?(\/|$)/.test(name)) {
      parts = [root, name].join('/').split('/');
    } else {
      parts = name.split('/');
    }
    for (var i = 0, length = parts.length; i < length; i++) {
      part = parts[i];
      if (part === '..') {
        results.pop();
      } else if (part !== '.' && part !== '') {
        results.push(part);
      }
    }
    return results.join('/');
  };

  var dirname = function(path) {
    return path.split('/').slice(0, -1).join('/');
  };

  var localRequire = function(path) {
    return function(name) {
      var dir = dirname(path);
      var absolute = expand(dir, name);
      return globals.require(absolute);
    };
  };

  var initModule = function(name, definition) {
    var module = {id: name, exports: {}};
    definition(module.exports, localRequire(name), module);
    var exports = cache[name] = module.exports;
    return exports;
  };

  var require = function(name) {
    var path = expand(name, '.');

    if (has(cache, path)) return cache[path];
    if (has(modules, path)) return initModule(path, modules[path]);

    var dirIndex = expand(path, './index');
    if (has(cache, dirIndex)) return cache[dirIndex];
    if (has(modules, dirIndex)) return initModule(dirIndex, modules[dirIndex]);

    throw new Error('Cannot find module "' + name + '"');
  };

  var define = function(bundle, fn) {
    if (typeof bundle === 'object') {
      for (var key in bundle) {
        if (has(bundle, key)) {
          modules[key] = bundle[key];
        }
      }
    } else {
      modules[bundle] = fn;
    }
  }

  globals.require = require;
  globals.require.define = define;
  globals.require.brunch = true;
})();

// Make it safe to do console.log() always.
(function (con) {
  var method;
  var dummy = function() {};
  var methods = ('assert,count,debug,dir,dirxml,error,exception,group,' +
     'groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,' + 
     'time,timeEnd,trace,warn').split(',');
  while (method = methods.pop()) {
    con[method] = con[method] || dummy;
  }
})(window.console = window.console || {});
;

//     Backbone.js 0.9.2

//     (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
//     Backbone may be freely distributed under the MIT license.
//     For all details and documentation:
//     http://backbonejs.org

(function(){

  // Initial Setup
  // -------------

  // Save a reference to the global object (`window` in the browser, `global`
  // on the server).
  var root = this;

  // Save the previous value of the `Backbone` variable, so that it can be
  // restored later on, if `noConflict` is used.
  var previousBackbone = root.Backbone;

  // Create a local reference to slice/splice.
  var slice = Array.prototype.slice;
  var splice = Array.prototype.splice;

  // The top-level namespace. All public Backbone classes and modules will
  // be attached to this. Exported for both CommonJS and the browser.
  var Backbone;
  if (typeof exports !== 'undefined') {
    Backbone = exports;
  } else {
    Backbone = root.Backbone = {};
  }

  // Current version of the library. Keep in sync with `package.json`.
  Backbone.VERSION = '0.9.2';

  // Require Underscore, if we're on the server, and it's not already present.
  var _ = root._;
  if (!_ && (typeof require !== 'undefined')) _ = require('underscore');

  // For Backbone's purposes, jQuery, Zepto, or Ender owns the `$` variable.
  var $ = root.jQuery || root.Zepto || root.ender;

  // Set the JavaScript library that will be used for DOM manipulation and
  // Ajax calls (a.k.a. the `$` variable). By default Backbone will use: jQuery,
  // Zepto, or Ender; but the `setDomLibrary()` method lets you inject an
  // alternate JavaScript library (or a mock library for testing your views
  // outside of a browser).
  Backbone.setDomLibrary = function(lib) {
    $ = lib;
  };

  // Runs Backbone.js in *noConflict* mode, returning the `Backbone` variable
  // to its previous owner. Returns a reference to this Backbone object.
  Backbone.noConflict = function() {
    root.Backbone = previousBackbone;
    return this;
  };

  // Turn on `emulateHTTP` to support legacy HTTP servers. Setting this option
  // will fake `"PUT"` and `"DELETE"` requests via the `_method` parameter and
  // set a `X-Http-Method-Override` header.
  Backbone.emulateHTTP = false;

  // Turn on `emulateJSON` to support legacy servers that can't deal with direct
  // `application/json` requests ... will encode the body as
  // `application/x-www-form-urlencoded` instead and will send the model in a
  // form param named `model`.
  Backbone.emulateJSON = false;

  // Backbone.Events
  // -----------------

  // Regular expression used to split event strings
  var eventSplitter = /\s+/;

  // A module that can be mixed in to *any object* in order to provide it with
  // custom events. You may bind with `on` or remove with `off` callback functions
  // to an event; trigger`-ing an event fires all callbacks in succession.
  //
  //     var object = {};
  //     _.extend(object, Backbone.Events);
  //     object.on('expand', function(){ alert('expanded'); });
  //     object.trigger('expand');
  //
  var Events = Backbone.Events = {

    // Bind one or more space separated events, `events`, to a `callback`
    // function. Passing `"all"` will bind the callback to all events fired.
    on: function(events, callback, context) {

      var calls, event, node, tail, list;
      if (!callback) return this;
      events = events.split(eventSplitter);
      calls = this._callbacks || (this._callbacks = {});

      // Create an immutable callback list, allowing traversal during
      // modification.  The tail is an empty object that will always be used
      // as the next node.
      while (event = events.shift()) {
        list = calls[event];
        node = list ? list.tail : {};
        node.next = tail = {};
        node.context = context;
        node.callback = callback;
        calls[event] = {tail: tail, next: list ? list.next : node};
      }

      return this;
    },

    // Remove one or many callbacks. If `context` is null, removes all callbacks
    // with that function. If `callback` is null, removes all callbacks for the
    // event. If `events` is null, removes all bound callbacks for all events.
    off: function(events, callback, context) {
      var event, calls, node, tail, cb, ctx;

      // No events, or removing *all* events.
      if (!(calls = this._callbacks)) return;
      if (!(events || callback || context)) {
        delete this._callbacks;
        return this;
      }

      // Loop through the listed events and contexts, splicing them out of the
      // linked list of callbacks if appropriate.
      events = events ? events.split(eventSplitter) : _.keys(calls);
      while (event = events.shift()) {
        node = calls[event];
        delete calls[event];
        if (!node || !(callback || context)) continue;
        // Create a new list, omitting the indicated callbacks.
        tail = node.tail;
        while ((node = node.next) !== tail) {
          cb = node.callback;
          ctx = node.context;
          if ((callback && cb !== callback) || (context && ctx !== context)) {
            this.on(event, cb, ctx);
          }
        }
      }

      return this;
    },

    // Trigger one or many events, firing all bound callbacks. Callbacks are
    // passed the same arguments as `trigger` is, apart from the event name
    // (unless you're listening on `"all"`, which will cause your callback to
    // receive the true name of the event as the first argument).
    trigger: function(events) {
      var event, node, calls, tail, args, all, rest;
      if (!(calls = this._callbacks)) return this;
      all = calls.all;
      events = events.split(eventSplitter);
      rest = slice.call(arguments, 1);

      // For each event, walk through the linked list of callbacks twice,
      // first to trigger the event, then to trigger any `"all"` callbacks.
      while (event = events.shift()) {
        if (node = calls[event]) {
          tail = node.tail;
          while ((node = node.next) !== tail) {
            node.callback.apply(node.context || this, rest);
          }
        }
        if (node = all) {
          tail = node.tail;
          args = [event].concat(rest);
          while ((node = node.next) !== tail) {
            node.callback.apply(node.context || this, args);
          }
        }
      }

      return this;
    }

  };

  // Aliases for backwards compatibility.
  Events.bind   = Events.on;
  Events.unbind = Events.off;

  // Backbone.Model
  // --------------

  // Create a new model, with defined attributes. A client id (`cid`)
  // is automatically generated and assigned for you.
  var Model = Backbone.Model = function(attributes, options) {
    var defaults;
    attributes || (attributes = {});
    if (options && options.parse) attributes = this.parse(attributes);
    if (defaults = getValue(this, 'defaults')) {
      attributes = _.extend({}, defaults, attributes);
    }
    if (options && options.collection) this.collection = options.collection;
    this.attributes = {};
    this._escapedAttributes = {};
    this.cid = _.uniqueId('c');
    this.changed = {};
    this._silent = {};
    this._pending = {};
    this.set(attributes, {silent: true});
    // Reset change tracking.
    this.changed = {};
    this._silent = {};
    this._pending = {};
    this._previousAttributes = _.clone(this.attributes);
    this.initialize.apply(this, arguments);
  };

  // Attach all inheritable methods to the Model prototype.
  _.extend(Model.prototype, Events, {

    // A hash of attributes whose current and previous value differ.
    changed: null,

    // A hash of attributes that have silently changed since the last time
    // `change` was called.  Will become pending attributes on the next call.
    _silent: null,

    // A hash of attributes that have changed since the last `'change'` event
    // began.
    _pending: null,

    // The default name for the JSON `id` attribute is `"id"`. MongoDB and
    // CouchDB users may want to set this to `"_id"`.
    idAttribute: 'id',

    // Initialize is an empty function by default. Override it with your own
    // initialization logic.
    initialize: function(){},

    // Return a copy of the model's `attributes` object.
    toJSON: function(options) {
      return _.clone(this.attributes);
    },

    // Get the value of an attribute.
    get: function(attr) {
      return this.attributes[attr];
    },

    // Get the HTML-escaped value of an attribute.
    escape: function(attr) {
      var html;
      if (html = this._escapedAttributes[attr]) return html;
      var val = this.get(attr);
      return this._escapedAttributes[attr] = _.escape(val == null ? '' : '' + val);
    },

    // Returns `true` if the attribute contains a value that is not null
    // or undefined.
    has: function(attr) {
      return this.get(attr) != null;
    },

    // Set a hash of model attributes on the object, firing `"change"` unless
    // you choose to silence it.
    set: function(key, value, options) {
      var attrs, attr, val;

      // Handle both
      if (_.isObject(key) || key == null) {
        attrs = key;
        options = value;
      } else {
        attrs = {};
        attrs[key] = value;
      }

      // Extract attributes and options.
      options || (options = {});
      if (!attrs) return this;
      if (attrs instanceof Model) attrs = attrs.attributes;
      if (options.unset) for (attr in attrs) attrs[attr] = void 0;

      // Run validation.
      if (!this._validate(attrs, options)) return false;

      // Check for changes of `id`.
      if (this.idAttribute in attrs) this.id = attrs[this.idAttribute];

      var changes = options.changes = {};
      var now = this.attributes;
      var escaped = this._escapedAttributes;
      var prev = this._previousAttributes || {};

      // For each `set` attribute...
      for (attr in attrs) {
        val = attrs[attr];

        // If the new and current value differ, record the change.
        if (!_.isEqual(now[attr], val) || (options.unset && _.has(now, attr))) {
          delete escaped[attr];
          (options.silent ? this._silent : changes)[attr] = true;
        }

        // Update or delete the current value.
        options.unset ? delete now[attr] : now[attr] = val;

        // If the new and previous value differ, record the change.  If not,
        // then remove changes for this attribute.
        if (!_.isEqual(prev[attr], val) || (_.has(now, attr) != _.has(prev, attr))) {
          this.changed[attr] = val;
          if (!options.silent) this._pending[attr] = true;
        } else {
          delete this.changed[attr];
          delete this._pending[attr];
        }
      }

      // Fire the `"change"` events.
      if (!options.silent) this.change(options);
      return this;
    },

    // Remove an attribute from the model, firing `"change"` unless you choose
    // to silence it. `unset` is a noop if the attribute doesn't exist.
    unset: function(attr, options) {
      (options || (options = {})).unset = true;
      return this.set(attr, null, options);
    },

    // Clear all attributes on the model, firing `"change"` unless you choose
    // to silence it.
    clear: function(options) {
      (options || (options = {})).unset = true;
      return this.set(_.clone(this.attributes), options);
    },

    // Fetch the model from the server. If the server's representation of the
    // model differs from its current attributes, they will be overriden,
    // triggering a `"change"` event.
    fetch: function(options) {
      options = options ? _.clone(options) : {};
      var model = this;
      var success = options.success;
      options.success = function(resp, status, xhr) {
        if (!model.set(model.parse(resp, xhr), options)) return false;
        if (success) success(model, resp);
      };
      options.error = Backbone.wrapError(options.error, model, options);
      return (this.sync || Backbone.sync).call(this, 'read', this, options);
    },

    // Set a hash of model attributes, and sync the model to the server.
    // If the server returns an attributes hash that differs, the model's
    // state will be `set` again.
    save: function(key, value, options) {
      var attrs, current;

      // Handle both `("key", value)` and `({key: value})` -style calls.
      if (_.isObject(key) || key == null) {
        attrs = key;
        options = value;
      } else {
        attrs = {};
        attrs[key] = value;
      }
      options = options ? _.clone(options) : {};

      // If we're "wait"-ing to set changed attributes, validate early.
      if (options.wait) {
        if (!this._validate(attrs, options)) return false;
        current = _.clone(this.attributes);
      }

      // Regular saves `set` attributes before persisting to the server.
      var silentOptions = _.extend({}, options, {silent: true});
      if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) {
        return false;
      }

      // After a successful server-side save, the client is (optionally)
      // updated with the server-side state.
      var model = this;
      var success = options.success;
      options.success = function(resp, status, xhr) {
        var serverAttrs = model.parse(resp, xhr);
        if (options.wait) {
          delete options.wait;
          serverAttrs = _.extend(attrs || {}, serverAttrs);
        }
        if (!model.set(serverAttrs, options)) return false;
        if (success) {
          success(model, resp);
        } else {
          model.trigger('sync', model, resp, options);
        }
      };

      // Finish configuring and sending the Ajax request.
      options.error = Backbone.wrapError(options.error, model, options);
      var method = this.isNew() ? 'create' : 'update';
      var xhr = (this.sync || Backbone.sync).call(this, method, this, options);
      if (options.wait) this.set(current, silentOptions);
      return xhr;
    },

    // Destroy this model on the server if it was already persisted.
    // Optimistically removes the model from its collection, if it has one.
    // If `wait: true` is passed, waits for the server to respond before removal.
    destroy: function(options) {
      options = options ? _.clone(options) : {};
      var model = this;
      var success = options.success;

      var triggerDestroy = function() {
        model.trigger('destroy', model, model.collection, options);
      };

      if (this.isNew()) {
        triggerDestroy();
        return false;
      }

      options.success = function(resp) {
        if (options.wait) triggerDestroy();
        if (success) {
          success(model, resp);
        } else {
          model.trigger('sync', model, resp, options);
        }
      };

      options.error = Backbone.wrapError(options.error, model, options);
      var xhr = (this.sync || Backbone.sync).call(this, 'delete', this, options);
      if (!options.wait) triggerDestroy();
      return xhr;
    },

    // Default URL for the model's representation on the server -- if you're
    // using Backbone's restful methods, override this to change the endpoint
    // that will be called.
    url: function() {
      var base = getValue(this, 'urlRoot') || getValue(this.collection, 'url') || urlError();
      if (this.isNew()) return base;
      return base + (base.charAt(base.length - 1) == '/' ? '' : '/') + encodeURIComponent(this.id);
    },

    // **parse** converts a response into the hash of attributes to be `set` on
    // the model. The default implementation is just to pass the response along.
    parse: function(resp, xhr) {
      return resp;
    },

    // Create a new model with identical attributes to this one.
    clone: function() {
      return new this.constructor(this.attributes);
    },

    // A model is new if it has never been saved to the server, and lacks an id.
    isNew: function() {
      return this.id == null;
    },

    // Call this method to manually fire a `"change"` event for this model and
    // a `"change:attribute"` event for each changed attribute.
    // Calling this will cause all objects observing the model to update.
    change: function(options) {
      options || (options = {});
      var changing = this._changing;
      this._changing = true;

      // Silent changes become pending changes.
      for (var attr in this._silent) this._pending[attr] = true;

      // Silent changes are triggered.
      var changes = _.extend({}, options.changes, this._silent);
      this._silent = {};
      for (var attr in changes) {
        this.trigger('change:' + attr, this, this.get(attr), options);
      }
      if (changing) return this;

      // Continue firing `"change"` events while there are pending changes.
      while (!_.isEmpty(this._pending)) {
        this._pending = {};
        this.trigger('change', this, options);
        // Pending and silent changes still remain.
        for (var attr in this.changed) {
          if (this._pending[attr] || this._silent[attr]) continue;
          delete this.changed[attr];
        }
        this._previousAttributes = _.clone(this.attributes);
      }

      this._changing = false;
      return this;
    },

    // Determine if the model has changed since the last `"change"` event.
    // If you specify an attribute name, determine if that attribute has changed.
    hasChanged: function(attr) {
      if (!arguments.length) return !_.isEmpty(this.changed);
      return _.has(this.changed, attr);
    },

    // Return an object containing all the attributes that have changed, or
    // false if there are no changed attributes. Useful for determining what
    // parts of a view need to be updated and/or what attributes need to be
    // persisted to the server. Unset attributes will be set to undefined.
    // You can also pass an attributes object to diff against the model,
    // determining if there *would be* a change.
    changedAttributes: function(diff) {
      if (!diff) return this.hasChanged() ? _.clone(this.changed) : false;
      var val, changed = false, old = this._previousAttributes;
      for (var attr in diff) {
        if (_.isEqual(old[attr], (val = diff[attr]))) continue;
        (changed || (changed = {}))[attr] = val;
      }
      return changed;
    },

    // Get the previous value of an attribute, recorded at the time the last
    // `"change"` event was fired.
    previous: function(attr) {
      if (!arguments.length || !this._previousAttributes) return null;
      return this._previousAttributes[attr];
    },

    // Get all of the attributes of the model at the time of the previous
    // `"change"` event.
    previousAttributes: function() {
      return _.clone(this._previousAttributes);
    },

    // Check if the model is currently in a valid state. It's only possible to
    // get into an *invalid* state if you're using silent changes.
    isValid: function() {
      return !this.validate(this.attributes);
    },

    // Run validation against the next complete set of model attributes,
    // returning `true` if all is well. If a specific `error` callback has
    // been passed, call that instead of firing the general `"error"` event.
    _validate: function(attrs, options) {
      if (options.silent || !this.validate) return true;
      attrs = _.extend({}, this.attributes, attrs);
      var error = this.validate(attrs, options);
      if (!error) return true;
      if (options && options.error) {
        options.error(this, error, options);
      } else {
        this.trigger('error', this, error, options);
      }
      return false;
    }

  });

  // Backbone.Collection
  // -------------------

  // Provides a standard collection class for our sets of models, ordered
  // or unordered. If a `comparator` is specified, the Collection will maintain
  // its models in sort order, as they're added and removed.
  var Collection = Backbone.Collection = function(models, options) {
    options || (options = {});
    if (options.model) this.model = options.model;
    if (options.comparator) this.comparator = options.comparator;
    this._reset();
    this.initialize.apply(this, arguments);
    if (models) this.reset(models, {silent: true, parse: options.parse});
  };

  // Define the Collection's inheritable methods.
  _.extend(Collection.prototype, Events, {

    // The default model for a collection is just a **Backbone.Model**.
    // This should be overridden in most cases.
    model: Model,

    // Initialize is an empty function by default. Override it with your own
    // initialization logic.
    initialize: function(){},

    // The JSON representation of a Collection is an array of the
    // models' attributes.
    toJSON: function(options) {
      return this.map(function(model){ return model.toJSON(options); });
    },

    // Add a model, or list of models to the set. Pass **silent** to avoid
    // firing the `add` event for every new model.
    add: function(models, options) {
      var i, index, length, model, cid, id, cids = {}, ids = {}, dups = [];
      options || (options = {});
      models = _.isArray(models) ? models.slice() : [models];

      // Begin by turning bare objects into model references, and preventing
      // invalid models or duplicate models from being added.
      for (i = 0, length = models.length; i < length; i++) {
        if (!(model = models[i] = this._prepareModel(models[i], options))) {
          throw new Error("Can't add an invalid model to a collection");
        }
        cid = model.cid;
        id = model.id;
        if (cids[cid] || this._byCid[cid] || ((id != null) && (ids[id] || this._byId[id]))) {
          dups.push(i);
          continue;
        }
        cids[cid] = ids[id] = model;
      }

      // Remove duplicates.
      i = dups.length;
      while (i--) {
        models.splice(dups[i], 1);
      }

      // Listen to added models' events, and index models for lookup by
      // `id` and by `cid`.
      for (i = 0, length = models.length; i < length; i++) {
        (model = models[i]).on('all', this._onModelEvent, this);
        this._byCid[model.cid] = model;
        if (model.id != null) this._byId[model.id] = model;
      }

      // Insert models into the collection, re-sorting if needed, and triggering
      // `add` events unless silenced.
      this.length += length;
      index = options.at != null ? options.at : this.models.length;
      splice.apply(this.models, [index, 0].concat(models));
      if (this.comparator) this.sort({silent: true});
      if (options.silent) return this;
      for (i = 0, length = this.models.length; i < length; i++) {
        if (!cids[(model = this.models[i]).cid]) continue;
        options.index = i;
        model.trigger('add', model, this, options);
      }
      return this;
    },

    // Remove a model, or a list of models from the set. Pass silent to avoid
    // firing the `remove` event for every model removed.
    remove: function(models, options) {
      var i, l, index, model;
      options || (options = {});
      models = _.isArray(models) ? models.slice() : [models];
      for (i = 0, l = models.length; i < l; i++) {
        model = this.getByCid(models[i]) || this.get(models[i]);
        if (!model) continue;
        delete this._byId[model.id];
        delete this._byCid[model.cid];
        index = this.indexOf(model);
        this.models.splice(index, 1);
        this.length--;
        if (!options.silent) {
          options.index = index;
          model.trigger('remove', model, this, options);
        }
        this._removeReference(model);
      }
      return this;
    },

    // Add a model to the end of the collection.
    push: function(model, options) {
      model = this._prepareModel(model, options);
      this.add(model, options);
      return model;
    },

    // Remove a model from the end of the collection.
    pop: function(options) {
      var model = this.at(this.length - 1);
      this.remove(model, options);
      return model;
    },

    // Add a model to the beginning of the collection.
    unshift: function(model, options) {
      model = this._prepareModel(model, options);
      this.add(model, _.extend({at: 0}, options));
      return model;
    },

    // Remove a model from the beginning of the collection.
    shift: function(options) {
      var model = this.at(0);
      this.remove(model, options);
      return model;
    },

    // Get a model from the set by id.
    get: function(id) {
      if (id == null) return void 0;
      return this._byId[id.id != null ? id.id : id];
    },

    // Get a model from the set by client id.
    getByCid: function(cid) {
      return cid && this._byCid[cid.cid || cid];
    },

    // Get the model at the given index.
    at: function(index) {
      return this.models[index];
    },

    // Return models with matching attributes. Useful for simple cases of `filter`.
    where: function(attrs) {
      if (_.isEmpty(attrs)) return [];
      return this.filter(function(model) {
        for (var key in attrs) {
          if (attrs[key] !== model.get(key)) return false;
        }
        return true;
      });
    },

    // Force the collection to re-sort itself. You don't need to call this under
    // normal circumstances, as the set will maintain sort order as each item
    // is added.
    sort: function(options) {
      options || (options = {});
      if (!this.comparator) throw new Error('Cannot sort a set without a comparator');
      var boundComparator = _.bind(this.comparator, this);
      if (this.comparator.length == 1) {
        this.models = this.sortBy(boundComparator);
      } else {
        this.models.sort(boundComparator);
      }
      if (!options.silent) this.trigger('reset', this, options);
      return this;
    },

    // Pluck an attribute from each model in the collection.
    pluck: function(attr) {
      return _.map(this.models, function(model){ return model.get(attr); });
    },

    // When you have more items than you want to add or remove individually,
    // you can reset the entire set with a new list of models, without firing
    // any `add` or `remove` events. Fires `reset` when finished.
    reset: function(models, options) {
      models  || (models = []);
      options || (options = {});
      for (var i = 0, l = this.models.length; i < l; i++) {
        this._removeReference(this.models[i]);
      }
      this._reset();
      this.add(models, _.extend({silent: true}, options));
      if (!options.silent) this.trigger('reset', this, options);
      return this;
    },

    // Fetch the default set of models for this collection, resetting the
    // collection when they arrive. If `add: true` is passed, appends the
    // models to the collection instead of resetting.
    fetch: function(options) {
      options = options ? _.clone(options) : {};
      if (options.parse === undefined) options.parse = true;
      var collection = this;
      var success = options.success;
      options.success = function(resp, status, xhr) {
        collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
        if (success) success(collection, resp);
      };
      options.error = Backbone.wrapError(options.error, collection, options);
      return (this.sync || Backbone.sync).call(this, 'read', this, options);
    },

    // Create a new instance of a model in this collection. Add the model to the
    // collection immediately, unless `wait: true` is passed, in which case we
    // wait for the server to agree.
    create: function(model, options) {
      var coll = this;
      options = options ? _.clone(options) : {};
      model = this._prepareModel(model, options);
      if (!model) return false;
      if (!options.wait) coll.add(model, options);
      var success = options.success;
      options.success = function(nextModel, resp, xhr) {
        if (options.wait) coll.add(nextModel, options);
        if (success) {
          success(nextModel, resp);
        } else {
          nextModel.trigger('sync', model, resp, options);
        }
      };
      model.save(null, options);
      return model;
    },

    // **parse** converts a response into a list of models to be added to the
    // collection. The default implementation is just to pass it through.
    parse: function(resp, xhr) {
      return resp;
    },

    // Proxy to _'s chain. Can't be proxied the same way the rest of the
    // underscore methods are proxied because it relies on the underscore
    // constructor.
    chain: function () {
      return _(this.models).chain();
    },

    // Reset all internal state. Called when the collection is reset.
    _reset: function(options) {
      this.length = 0;
      this.models = [];
      this._byId  = {};
      this._byCid = {};
    },

    // Prepare a model or hash of attributes to be added to this collection.
    _prepareModel: function(model, options) {
      options || (options = {});
      if (!(model instanceof Model)) {
        var attrs = model;
        options.collection = this;
        model = new this.model(attrs, options);
        if (!model._validate(model.attributes, options)) model = false;
      } else if (!model.collection) {
        model.collection = this;
      }
      return model;
    },

    // Internal method to remove a model's ties to a collection.
    _removeReference: function(model) {
      if (this == model.collection) {
        delete model.collection;
      }
      model.off('all', this._onModelEvent, this);
    },

    // Internal method called every time a model in the set fires an event.
    // Sets need to update their indexes when models change ids. All other
    // events simply proxy through. "add" and "remove" events that originate
    // in other collections are ignored.
    _onModelEvent: function(event, model, collection, options) {
      if ((event == 'add' || event == 'remove') && collection != this) return;
      if (event == 'destroy') {
        this.remove(model, options);
      }
      if (model && event === 'change:' + model.idAttribute) {
        delete this._byId[model.previous(model.idAttribute)];
        this._byId[model.id] = model;
      }
      this.trigger.apply(this, arguments);
    }

  });

  // Underscore methods that we want to implement on the Collection.
  var methods = ['forEach', 'each', 'map', 'reduce', 'reduceRight', 'find',
    'detect', 'filter', 'select', 'reject', 'every', 'all', 'some', 'any',
    'include', 'contains', 'invoke', 'max', 'min', 'sortBy', 'sortedIndex',
    'toArray', 'size', 'first', 'initial', 'rest', 'last', 'without', 'indexOf',
    'shuffle', 'lastIndexOf', 'isEmpty', 'groupBy'];

  // Mix in each Underscore method as a proxy to `Collection#models`.
  _.each(methods, function(method) {
    Collection.prototype[method] = function() {
      return _[method].apply(_, [this.models].concat(_.toArray(arguments)));
    };
  });

  // Backbone.Router
  // -------------------

  // Routers map faux-URLs to actions, and fire events when routes are
  // matched. Creating a new one sets its `routes` hash, if not set statically.
  var Router = Backbone.Router = function(options) {
    options || (options = {});
    if (options.routes) this.routes = options.routes;
    this._bindRoutes();
    this.initialize.apply(this, arguments);
  };

  // Cached regular expressions for matching named param parts and splatted
  // parts of route strings.
  var namedParam    = /:\w+/g;
  var splatParam    = /\*\w+/g;
  var escapeRegExp  = /[-[\]{}()+?.,\\^$|#\s]/g;

  // Set up all inheritable **Backbone.Router** properties and methods.
  _.extend(Router.prototype, Events, {

    // Initialize is an empty function by default. Override it with your own
    // initialization logic.
    initialize: function(){},

    // Manually bind a single named route to a callback. For example:
    //
    //     this.route('search/:query/p:num', 'search', function(query, num) {
    //       ...
    //     });
    //
    route: function(route, name, callback) {
      Backbone.history || (Backbone.history = new History);
      if (!_.isRegExp(route)) route = this._routeToRegExp(route);
      if (!callback) callback = this[name];
      Backbone.history.route(route, _.bind(function(fragment) {
        var args = this._extractParameters(route, fragment);
        callback && callback.apply(this, args);
        this.trigger.apply(this, ['route:' + name].concat(args));
        Backbone.history.trigger('route', this, name, args);
      }, this));
      return this;
    },

    // Simple proxy to `Backbone.history` to save a fragment into the history.
    navigate: function(fragment, options) {
      Backbone.history.navigate(fragment, options);
    },

    // Bind all defined routes to `Backbone.history`. We have to reverse the
    // order of the routes here to support behavior where the most general
    // routes can be defined at the bottom of the route map.
    _bindRoutes: function() {
      if (!this.routes) return;
      var routes = [];
      for (var route in this.routes) {
        routes.unshift([route, this.routes[route]]);
      }
      for (var i = 0, l = routes.length; i < l; i++) {
        this.route(routes[i][0], routes[i][1], this[routes[i][1]]);
      }
    },

    // Convert a route string into a regular expression, suitable for matching
    // against the current location hash.
    _routeToRegExp: function(route) {
      route = route.replace(escapeRegExp, '\\$&')
                   .replace(namedParam, '([^\/]+)')
                   .replace(splatParam, '(.*?)');
      return new RegExp('^' + route + '$');
    },

    // Given a route, and a URL fragment that it matches, return the array of
    // extracted parameters.
    _extractParameters: function(route, fragment) {
      return route.exec(fragment).slice(1);
    }

  });

  // Backbone.History
  // ----------------

  // Handles cross-browser history management, based on URL fragments. If the
  // browser does not support `onhashchange`, falls back to polling.
  var History = Backbone.History = function() {
    this.handlers = [];
    _.bindAll(this, 'checkUrl');
  };

  // Cached regex for cleaning leading hashes and slashes .
  var routeStripper = /^[#\/]/;

  // Cached regex for detecting MSIE.
  var isExplorer = /msie [\w.]+/;

  // Has the history handling already been started?
  History.started = false;

  // Set up all inheritable **Backbone.History** properties and methods.
  _.extend(History.prototype, Events, {

    // The default interval to poll for hash changes, if necessary, is
    // twenty times a second.
    interval: 50,

    // Gets the true hash value. Cannot use location.hash directly due to bug
    // in Firefox where location.hash will always be decoded.
    getHash: function(windowOverride) {
      var loc = windowOverride ? windowOverride.location : window.location;
      var match = loc.href.match(/#(.*)$/);
      return match ? match[1] : '';
    },

    // Get the cross-browser normalized URL fragment, either from the URL,
    // the hash, or the override.
    getFragment: function(fragment, forcePushState) {
      if (fragment == null) {
        if (this._hasPushState || forcePushState) {
          fragment = window.location.pathname;
          var search = window.location.search;
          if (search) fragment += search;
        } else {
          fragment = this.getHash();
        }
      }
      if (!fragment.indexOf(this.options.root)) fragment = fragment.substr(this.options.root.length);
      return fragment.replace(routeStripper, '');
    },

    // Start the hash change handling, returning `true` if the current URL matches
    // an existing route, and `false` otherwise.
    start: function(options) {
      if (History.started) throw new Error("Backbone.history has already been started");
      History.started = true;

      // Figure out the initial configuration. Do we need an iframe?
      // Is pushState desired ... is it available?
      this.options          = _.extend({}, {root: '/'}, this.options, options);
      this._wantsHashChange = this.options.hashChange !== false;
      this._wantsPushState  = !!this.options.pushState;
      this._hasPushState    = !!(this.options.pushState && window.history && window.history.pushState);
      var fragment          = this.getFragment();
      var docMode           = document.documentMode;
      var oldIE             = (isExplorer.exec(navigator.userAgent.toLowerCase()) && (!docMode || docMode <= 7));

      if (oldIE) {
        this.iframe = $('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo('body')[0].contentWindow;
        this.navigate(fragment);
      }

      // Depending on whether we're using pushState or hashes, and whether
      // 'onhashchange' is supported, determine how we check the URL state.
      if (this._hasPushState) {
        $(window).bind('popstate', this.checkUrl);
      } else if (this._wantsHashChange && ('onhashchange' in window) && !oldIE) {
        $(window).bind('hashchange', this.checkUrl);
      } else if (this._wantsHashChange) {
        this._checkUrlInterval = setInterval(this.checkUrl, this.interval);
      }

      // Determine if we need to change the base url, for a pushState link
      // opened by a non-pushState browser.
      this.fragment = fragment;
      var loc = window.location;
      var atRoot  = loc.pathname == this.options.root;

      // If we've started off with a route from a `pushState`-enabled browser,
      // but we're currently in a browser that doesn't support it...
      if (this._wantsHashChange && this._wantsPushState && !this._hasPushState && !atRoot) {
        this.fragment = this.getFragment(null, true);
        window.location.replace(this.options.root + '#' + this.fragment);
        // Return immediately as browser will do redirect to new url
        return true;

      // Or if we've started out with a hash-based route, but we're currently
      // in a browser where it could be `pushState`-based instead...
      } else if (this._wantsPushState && this._hasPushState && atRoot && loc.hash) {
        this.fragment = this.getHash().replace(routeStripper, '');
        window.history.replaceState({}, document.title, loc.protocol + '//' + loc.host + this.options.root + this.fragment);
      }

      if (!this.options.silent) {
        return this.loadUrl();
      }
    },

    // Disable Backbone.history, perhaps temporarily. Not useful in a real app,
    // but possibly useful for unit testing Routers.
    stop: function() {
      $(window).unbind('popstate', this.checkUrl).unbind('hashchange', this.checkUrl);
      clearInterval(this._checkUrlInterval);
      History.started = false;
    },

    // Add a route to be tested when the fragment changes. Routes added later
    // may override previous routes.
    route: function(route, callback) {
      this.handlers.unshift({route: route, callback: callback});
    },

    // Checks the current URL to see if it has changed, and if it has,
    // calls `loadUrl`, normalizing across the hidden iframe.
    checkUrl: function(e) {
      var current = this.getFragment();
      if (current == this.fragment && this.iframe) current = this.getFragment(this.getHash(this.iframe));
      if (current == this.fragment) return false;
      if (this.iframe) this.navigate(current);
      this.loadUrl() || this.loadUrl(this.getHash());
    },

    // Attempt to load the current URL fragment. If a route succeeds with a
    // match, returns `true`. If no defined routes matches the fragment,
    // returns `false`.
    loadUrl: function(fragmentOverride) {
      var fragment = this.fragment = this.getFragment(fragmentOverride);
      var matched = _.any(this.handlers, function(handler) {
        if (handler.route.test(fragment)) {
          handler.callback(fragment);
          return true;
        }
      });
      return matched;
    },

    // Save a fragment into the hash history, or replace the URL state if the
    // 'replace' option is passed. You are responsible for properly URL-encoding
    // the fragment in advance.
    //
    // The options object can contain `trigger: true` if you wish to have the
    // route callback be fired (not usually desirable), or `replace: true`, if
    // you wish to modify the current URL without adding an entry to the history.
    navigate: function(fragment, options) {
      if (!History.started) return false;
      if (!options || options === true) options = {trigger: options};
      var frag = (fragment || '').replace(routeStripper, '');
      if (this.fragment == frag) return;

      // If pushState is available, we use it to set the fragment as a real URL.
      if (this._hasPushState) {
        if (frag.indexOf(this.options.root) != 0) frag = this.options.root + frag;
        this.fragment = frag;
        window.history[options.replace ? 'replaceState' : 'pushState']({}, document.title, frag);

      // If hash changes haven't been explicitly disabled, update the hash
      // fragment to store history.
      } else if (this._wantsHashChange) {
        this.fragment = frag;
        this._updateHash(window.location, frag, options.replace);
        if (this.iframe && (frag != this.getFragment(this.getHash(this.iframe)))) {
          // Opening and closing the iframe tricks IE7 and earlier to push a history entry on hash-tag change.
          // When replace is true, we don't want this.
          if(!options.replace) this.iframe.document.open().close();
          this._updateHash(this.iframe.location, frag, options.replace);
        }

      // If you've told us that you explicitly don't want fallback hashchange-
      // based history, then `navigate` becomes a page refresh.
      } else {
        window.location.assign(this.options.root + fragment);
      }
      if (options.trigger) this.loadUrl(fragment);
    },

    // Update the hash location, either replacing the current entry, or adding
    // a new one to the browser history.
    _updateHash: function(location, fragment, replace) {
      if (replace) {
        location.replace(location.toString().replace(/(javascript:|#).*$/, '') + '#' + fragment);
      } else {
        location.hash = fragment;
      }
    }
  });

  // Backbone.View
  // -------------

  // Creating a Backbone.View creates its initial element outside of the DOM,
  // if an existing element is not provided...
  var View = Backbone.View = function(options) {
    this.cid = _.uniqueId('view');
    this._configure(options || {});
    this._ensureElement();
    this.initialize.apply(this, arguments);
    this.delegateEvents();
  };

  // Cached regex to split keys for `delegate`.
  var delegateEventSplitter = /^(\S+)\s*(.*)$/;

  // List of view options to be merged as properties.
  var viewOptions = ['model', 'collection', 'el', 'id', 'attributes', 'className', 'tagName'];

  // Set up all inheritable **Backbone.View** properties and methods.
  _.extend(View.prototype, Events, {

    // The default `tagName` of a View's element is `"div"`.
    tagName: 'div',

    // jQuery delegate for element lookup, scoped to DOM elements within the
    // current view. This should be prefered to global lookups where possible.
    $: function(selector) {
      return this.$el.find(selector);
    },

    // Initialize is an empty function by default. Override it with your own
    // initialization logic.
    initialize: function(){},

    // **render** is the core function that your view should override, in order
    // to populate its element (`this.el`), with the appropriate HTML. The
    // convention is for **render** to always return `this`.
    render: function() {
      return this;
    },

    // Remove this view from the DOM. Note that the view isn't present in the
    // DOM by default, so calling this method may be a no-op.
    remove: function() {
      this.$el.remove();
      return this;
    },

    // For small amounts of DOM Elements, where a full-blown template isn't
    // needed, use **make** to manufacture elements, one at a time.
    //
    //     var el = this.make('li', {'class': 'row'}, this.model.escape('title'));
    //
    make: function(tagName, attributes, content) {
      var el = document.createElement(tagName);
      if (attributes) $(el).attr(attributes);
      if (content) $(el).html(content);
      return el;
    },

    // Change the view's element (`this.el` property), including event
    // re-delegation.
    setElement: function(element, delegate) {
      if (this.$el) this.undelegateEvents();
      this.$el = (element instanceof $) ? element : $(element);
      this.el = this.$el[0];
      if (delegate !== false) this.delegateEvents();
      return this;
    },

    // Set callbacks, where `this.events` is a hash of
    //
    // *{"event selector": "callback"}*
    //
    //     {
    //       'mousedown .title':  'edit',
    //       'click .button':     'save'
    //       'click .open':       function(e) { ... }
    //     }
    //
    // pairs. Callbacks will be bound to the view, with `this` set properly.
    // Uses event delegation for efficiency.
    // Omitting the selector binds the event to `this.el`.
    // This only works for delegate-able events: not `focus`, `blur`, and
    // not `change`, `submit`, and `reset` in Internet Explorer.
    delegateEvents: function(events) {
      if (!(events || (events = getValue(this, 'events')))) return;
      this.undelegateEvents();
      for (var key in events) {
        var method = events[key];
        if (!_.isFunction(method)) method = this[events[key]];
        if (!method) throw new Error('Method "' + events[key] + '" does not exist');
        var match = key.match(delegateEventSplitter);
        var eventName = match[1], selector = match[2];
        method = _.bind(method, this);
        eventName += '.delegateEvents' + this.cid;
        if (selector === '') {
          this.$el.bind(eventName, method);
        } else {
          this.$el.delegate(selector, eventName, method);
        }
      }
    },

    // Clears all callbacks previously bound to the view with `delegateEvents`.
    // You usually don't need to use this, but may wish to if you have multiple
    // Backbone views attached to the same DOM element.
    undelegateEvents: function() {
      this.$el.unbind('.delegateEvents' + this.cid);
    },

    // Performs the initial configuration of a View with a set of options.
    // Keys with special meaning *(model, collection, id, className)*, are
    // attached directly to the view.
    _configure: function(options) {
      if (this.options) options = _.extend({}, this.options, options);
      for (var i = 0, l = viewOptions.length; i < l; i++) {
        var attr = viewOptions[i];
        if (options[attr]) this[attr] = options[attr];
      }
      this.options = options;
    },

    // Ensure that the View has a DOM element to render into.
    // If `this.el` is a string, pass it through `$()`, take the first
    // matching element, and re-assign it to `el`. Otherwise, create
    // an element from the `id`, `className` and `tagName` properties.
    _ensureElement: function() {
      if (!this.el) {
        var attrs = getValue(this, 'attributes') || {};
        if (this.id) attrs.id = this.id;
        if (this.className) attrs['class'] = this.className;
        this.setElement(this.make(this.tagName, attrs), false);
      } else {
        this.setElement(this.el, false);
      }
    }

  });

  // The self-propagating extend function that Backbone classes use.
  var extend = function (protoProps, classProps) {
    var child = inherits(this, protoProps, classProps);
    child.extend = this.extend;
    return child;
  };

  // Set up inheritance for the model, collection, and view.
  Model.extend = Collection.extend = Router.extend = View.extend = extend;

  // Backbone.sync
  // -------------

  // Map from CRUD to HTTP for our default `Backbone.sync` implementation.
  var methodMap = {
    'create': 'POST',
    'update': 'PUT',
    'delete': 'DELETE',
    'read':   'GET'
  };

  // Override this function to change the manner in which Backbone persists
  // models to the server. You will be passed the type of request, and the
  // model in question. By default, makes a RESTful Ajax request
  // to the model's `url()`. Some possible customizations could be:
  //
  // * Use `setTimeout` to batch rapid-fire updates into a single request.
  // * Send up the models as XML instead of JSON.
  // * Persist models via WebSockets instead of Ajax.
  //
  // Turn on `Backbone.emulateHTTP` in order to send `PUT` and `DELETE` requests
  // as `POST`, with a `_method` parameter containing the true HTTP method,
  // as well as all requests with the body as `application/x-www-form-urlencoded`
  // instead of `application/json` with the model in a param named `model`.
  // Useful when interfacing with server-side languages like **PHP** that make
  // it difficult to read the body of `PUT` requests.
  Backbone.sync = function(method, model, options) {
    var type = methodMap[method];

    // Default options, unless specified.
    options || (options = {});

    // Default JSON-request options.
    var params = {type: type, dataType: 'json'};

    // Ensure that we have a URL.
    if (!options.url) {
      params.url = getValue(model, 'url') || urlError();
    }

    // Ensure that we have the appropriate request data.
    if (!options.data && model && (method == 'create' || method == 'update')) {
      params.contentType = 'application/json';
      params.data = JSON.stringify(model.toJSON());
    }

    // For older servers, emulate JSON by encoding the request into an HTML-form.
    if (Backbone.emulateJSON) {
      params.contentType = 'application/x-www-form-urlencoded';
      params.data = params.data ? {model: params.data} : {};
    }

    // For older servers, emulate HTTP by mimicking the HTTP method with `_method`
    // And an `X-HTTP-Method-Override` header.
    if (Backbone.emulateHTTP) {
      if (type === 'PUT' || type === 'DELETE') {
        if (Backbone.emulateJSON) params.data._method = type;
        params.type = 'POST';
        params.beforeSend = function(xhr) {
          xhr.setRequestHeader('X-HTTP-Method-Override', type);
        };
      }
    }

    // Don't process data on a non-GET request.
    if (params.type !== 'GET' && !Backbone.emulateJSON) {
      params.processData = false;
    }

    // Make the request, allowing the user to override any Ajax options.
    return $.ajax(_.extend(params, options));
  };

  // Wrap an optional error callback with a fallback error event.
  Backbone.wrapError = function(onError, originalModel, options) {
    return function(model, resp) {
      resp = model === originalModel ? resp : model;
      if (onError) {
        onError(originalModel, resp, options);
      } else {
        originalModel.trigger('error', originalModel, resp, options);
      }
    };
  };

  // Helpers
  // -------

  // Shared empty constructor function to aid in prototype-chain creation.
  var ctor = function(){};

  // Helper function to correctly set up the prototype chain, for subclasses.
  // Similar to `goog.inherits`, but uses a hash of prototype properties and
  // class properties to be extended.
  var inherits = function(parent, protoProps, staticProps) {
    var child;

    // The constructor function for the new subclass is either defined by you
    // (the "constructor" property in your `extend` definition), or defaulted
    // by us to simply call the parent's constructor.
    if (protoProps && protoProps.hasOwnProperty('constructor')) {
      child = protoProps.constructor;
    } else {
      child = function(){ parent.apply(this, arguments); };
    }

    // Inherit class (static) properties from parent.
    _.extend(child, parent);

    // Set the prototype chain to inherit from `parent`, without calling
    // `parent`'s constructor function.
    ctor.prototype = parent.prototype;
    child.prototype = new ctor();

    // Add prototype properties (instance properties) to the subclass,
    // if supplied.
    if (protoProps) _.extend(child.prototype, protoProps);

    // Add static properties to the constructor function, if supplied.
    if (staticProps) _.extend(child, staticProps);

    // Correctly set child's `prototype.constructor`.
    child.prototype.constructor = child;

    // Set a convenience property in case the parent's prototype is needed later.
    child.__super__ = parent.prototype;

    return child;
  };

  // Helper function to get a value from a Backbone object as a property
  // or as a function.
  var getValue = function(object, prop) {
    if (!(object && object[prop])) return null;
    return _.isFunction(object[prop]) ? object[prop]() : object[prop];
  };

  // Throw an error when a URL is needed, and none is supplied.
  var urlError = function() {
    throw new Error('A "url" property or function must be specified');
  };

}).call(this);;

/**
 * Backbone localStorage Adapter
 * https://github.com/jeromegn/Backbone.localStorage
 */

(function() {
  // A simple module to replace `Backbone.sync` with *localStorage*-based
  // persistence. Models are given GUIDS, and saved into a JSON object. Simple
  // as that.

  // Hold reference to Underscore.js and Backbone.js in the closure in order
  // to make things work even if they are removed from the global namespace
  var _ = this._;
  var Backbone = this.Backbone;

  // Generate four random hex digits.
  function S4() {
    return (((1+Math.random())*0x10000)|0).toString(16).substring(1);
  };

  // Generate a pseudo-GUID by concatenating random hexadecimal.
  function guid() {
    return (S4()+S4()+"-"+S4()+"-"+S4()+"-"+S4()+"-"+S4()+S4()+S4());
  };

  // Our Store is represented by a single JS object in *localStorage*. Create it
  // with a meaningful name, like the name you'd give a table.
  // window.Store is deprectated, use Backbone.LocalStorage instead
  Backbone.LocalStorage = window.Store = function(name) {
    this.name = name;
    var store = this.localStorage().getItem(this.name);
    this.records = (store && store.split(",")) || [];
  };

  _.extend(Backbone.LocalStorage.prototype, {

    // Save the current state of the **Store** to *localStorage*.
    save: function() {
      this.localStorage().setItem(this.name, this.records.join(","));
    },

    // Add a model, giving it a (hopefully)-unique GUID, if it doesn't already
    // have an id of it's own.
    create: function(model) {
      if (!model.id) {
        model.id = guid();
        model.set(model.idAttribute, model.id);
      }
      this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
      this.records.push(model.id.toString());
      this.save();
      return model.toJSON();
    },

    // Update a model by replacing its copy in `this.data`.
    update: function(model) {
      this.localStorage().setItem(this.name+"-"+model.id, JSON.stringify(model));
      if (!_.include(this.records, model.id.toString())) this.records.push(model.id.toString()); this.save();
      return model.toJSON();
    },

    // Retrieve a model from `this.data` by id.
    find: function(model) {
      return JSON.parse(this.localStorage().getItem(this.name+"-"+model.id));
    },

    // Return the array of all models currently in storage.
    findAll: function() {
      return _(this.records).chain()
        .map(function(id){return JSON.parse(this.localStorage().getItem(this.name+"-"+id));}, this)
        .compact()
        .value();
    },

    // Delete a model from `this.data`, returning it.
    destroy: function(model) {
      this.localStorage().removeItem(this.name+"-"+model.id);
      this.records = _.reject(this.records, function(record_id){return record_id == model.id.toString();});
      this.save();
      return model;
    },

    localStorage: function() {
      return localStorage;
    }

  });

  // localSync delegate to the model or collection's
  // *localStorage* property, which should be an instance of `Store`.
  // window.Store.sync and Backbone.localSync is deprectated, use Backbone.LocalStorage.sync instead
  Backbone.LocalStorage.sync = window.Store.sync = Backbone.localSync = function(method, model, options, error) {
    var store = model.localStorage || model.collection.localStorage;

    // Backwards compatibility with Backbone <= 0.3.3
    if (typeof options == 'function') {
      options = {
        success: options,
        error: error
      };
    }

    var resp;

    switch (method) {
      case "read":    resp = model.id != undefined ? store.find(model) : store.findAll(); break;
      case "create":  resp = store.create(model);                            break;
      case "update":  resp = store.update(model);                            break;
      case "delete":  resp = store.destroy(model);                           break;
    }

    if (resp) {
      options.success(resp);
    } else {
      options.error("Record not found");
    }
  };

  Backbone.ajaxSync = Backbone.sync;

  Backbone.getSyncMethod = function(model) {
    if(model.localStorage || (model.collection && model.collection.localStorage))
    {
      return Backbone.localSync;
    }

    return Backbone.ajaxSync;
  };

  // Override 'Backbone.sync' to default to localSync,
  // the original 'Backbone.sync' is still available in 'Backbone.ajaxSync'
  Backbone.sync = function(method, model, options, error) {
    return Backbone.getSyncMethod(model).apply(this, [method, model, options, error]);
  };

})();
;

// lib/handlebars/base.js

/*jshint eqnull:true*/
this.Handlebars = {};

(function(Handlebars) {

Handlebars.VERSION = "1.0.rc.1";

Handlebars.helpers  = {};
Handlebars.partials = {};

Handlebars.registerHelper = function(name, fn, inverse) {
  if(inverse) { fn.not = inverse; }
  this.helpers[name] = fn;
};

Handlebars.registerPartial = function(name, str) {
  this.partials[name] = str;
};

Handlebars.registerHelper('helperMissing', function(arg) {
  if(arguments.length === 2) {
    return undefined;
  } else {
    throw new Error("Could not find property '" + arg + "'");
  }
});

var toString = Object.prototype.toString, functionType = "[object Function]";

Handlebars.registerHelper('blockHelperMissing', function(context, options) {
  var inverse = options.inverse || function() {}, fn = options.fn;


  var ret = "";
  var type = toString.call(context);

  if(type === functionType) { context = context.call(this); }

  if(context === true) {
    return fn(this);
  } else if(context === false || context == null) {
    return inverse(this);
  } else if(type === "[object Array]") {
    if(context.length > 0) {
      return Handlebars.helpers.each(context, options);
    } else {
      return inverse(this);
    }
  } else {
    return fn(context);
  }
});

Handlebars.K = function() {};

Handlebars.createFrame = Object.create || function(object) {
  Handlebars.K.prototype = object;
  var obj = new Handlebars.K();
  Handlebars.K.prototype = null;
  return obj;
};

Handlebars.registerHelper('each', function(context, options) {
  var fn = options.fn, inverse = options.inverse;
  var ret = "", data;

  if (options.data) {
    data = Handlebars.createFrame(options.data);
  }

  if(context && context.length > 0) {
    for(var i=0, j=context.length; i<j; i++) {
      if (data) { data.index = i; }
      ret = ret + fn(context[i], { data: data });
    }
  } else {
    ret = inverse(this);
  }
  return ret;
});

Handlebars.registerHelper('if', function(context, options) {
  var type = toString.call(context);
  if(type === functionType) { context = context.call(this); }

  if(!context || Handlebars.Utils.isEmpty(context)) {
    return options.inverse(this);
  } else {
    return options.fn(this);
  }
});

Handlebars.registerHelper('unless', function(context, options) {
  var fn = options.fn, inverse = options.inverse;
  options.fn = inverse;
  options.inverse = fn;

  return Handlebars.helpers['if'].call(this, context, options);
});

Handlebars.registerHelper('with', function(context, options) {
  return options.fn(context);
});

Handlebars.registerHelper('log', function(context) {
  Handlebars.log(context);
});

}(this.Handlebars));
;
// lib/handlebars/utils.js
Handlebars.Exception = function(message) {
  var tmp = Error.prototype.constructor.apply(this, arguments);

  for (var p in tmp) {
    if (tmp.hasOwnProperty(p)) { this[p] = tmp[p]; }
  }

  this.message = tmp.message;
};
Handlebars.Exception.prototype = new Error();

// Build out our basic SafeString type
Handlebars.SafeString = function(string) {
  this.string = string;
};
Handlebars.SafeString.prototype.toString = function() {
  return this.string.toString();
};

(function() {
  var escape = {
    "&": "&amp;",
    "<": "&lt;",
    ">": "&gt;",
    '"': "&quot;",
    "'": "&#x27;",
    "`": "&#x60;"
  };

  var badChars = /[&<>"'`]/g;
  var possible = /[&<>"'`]/;

  var escapeChar = function(chr) {
    return escape[chr] || "&amp;";
  };

  Handlebars.Utils = {
    escapeExpression: function(string) {
      // don't escape SafeStrings, since they're already safe
      if (string instanceof Handlebars.SafeString) {
        return string.toString();
      } else if (string == null || string === false) {
        return "";
      }

      if(!possible.test(string)) { return string; }
      return string.replace(badChars, escapeChar);
    },

    isEmpty: function(value) {
      if (typeof value === "undefined") {
        return true;
      } else if (value === null) {
        return true;
      } else if (value === false) {
        return true;
      } else if(Object.prototype.toString.call(value) === "[object Array]" && value.length === 0) {
        return true;
      } else {
        return false;
      }
    }
  };
})();;
// lib/handlebars/runtime.js
Handlebars.VM = {
  template: function(templateSpec) {
    // Just add water
    var container = {
      escapeExpression: Handlebars.Utils.escapeExpression,
      invokePartial: Handlebars.VM.invokePartial,
      programs: [],
      program: function(i, fn, data) {
        var programWrapper = this.programs[i];
        if(data) {
          return Handlebars.VM.program(fn, data);
        } else if(programWrapper) {
          return programWrapper;
        } else {
          programWrapper = this.programs[i] = Handlebars.VM.program(fn);
          return programWrapper;
        }
      },
      programWithDepth: Handlebars.VM.programWithDepth,
      noop: Handlebars.VM.noop
    };

    return function(context, options) {
      options = options || {};
      return templateSpec.call(container, Handlebars, context, options.helpers, options.partials, options.data);
    };
  },

  programWithDepth: function(fn, data, $depth) {
    var args = Array.prototype.slice.call(arguments, 2);

    return function(context, options) {
      options = options || {};

      return fn.apply(this, [context, options.data || data].concat(args));
    };
  },
  program: function(fn, data) {
    return function(context, options) {
      options = options || {};

      return fn(context, options.data || data);
    };
  },
  noop: function() { return ""; },
  invokePartial: function(partial, name, context, helpers, partials, data) {
    var options = { helpers: helpers, partials: partials, data: data };

    if(partial === undefined) {
      throw new Handlebars.Exception("The partial " + name + " could not be found");
    } else if(partial instanceof Function) {
      return partial(context, options);
    } else if (!Handlebars.compile) {
      throw new Handlebars.Exception("The partial " + name + " could not be compiled when running in runtime-only mode");
    } else {
      partials[name] = Handlebars.compile(partial, {data: data !== undefined});
      return partials[name](context, options);
    }
  }
};

Handlebars.template = Handlebars.VM.template;
;
;

/*
Chaplin 0.5.0.

Chaplin may be freely distributed under the MIT license.
For all details and documentation:
http://github.com/chaplinjs/chaplin
*/

'use strict';

var __hasProp = {}.hasOwnProperty,
  __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
  __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
  __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
  __slice = [].slice;

require.define({
  'jquery': function(require, exports, module) {
    return module.exports = $;
  },
  'underscore': function(require, exports, module) {
    return module.exports = _;
  },
  'backbone': function(require, exports, module) {
    return module.exports = Backbone;
  }
});

require.define({
  'chaplin/application': function(exports, require, module) {
    var Application, Backbone, Dispatcher, EventBroker, Layout, Router, mediator;
    Backbone = require('backbone');
    mediator = require('chaplin/mediator');
    Dispatcher = require('chaplin/dispatcher');
    Layout = require('chaplin/views/layout');
    Router = require('chaplin/lib/router');
    EventBroker = require('chaplin/lib/event_broker');
    return module.exports = Application = (function() {

      function Application() {}

      Application.extend = Backbone.Model.extend;

      _(Application.prototype).extend(EventBroker);

      Application.prototype.title = '';

      Application.prototype.dispatcher = null;

      Application.prototype.layout = null;

      Application.prototype.router = null;

      Application.prototype.initialize = function() {};

      Application.prototype.initDispatcher = function(options) {
        return this.dispatcher = new Dispatcher(options);
      };

      Application.prototype.initLayout = function(options) {
        var _ref;
        if (options == null) {
          options = {};
        }
        if ((_ref = options.title) == null) {
          options.title = this.title;
        }
        return this.layout = new Layout(options);
      };

      Application.prototype.initRouter = function(routes, options) {
        this.router = new Router(options);
        if (typeof routes === "function") {
          routes(this.router.match);
        }
        return this.router.startHistory();
      };

      Application.prototype.disposed = false;

      Application.prototype.dispose = function() {
        var prop, properties, _i, _len;
        if (this.disposed) {
          return;
        }
        properties = ['dispatcher', 'layout', 'router'];
        for (_i = 0, _len = properties.length; _i < _len; _i++) {
          prop = properties[_i];
          if (!(this[prop] != null)) {
            continue;
          }
          this[prop].dispose();
          delete this[prop];
        }
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Application;

    })();
  }
});

require.define({
  'chaplin/mediator': function(exports, require, module) {
    var Backbone, mediator, support, utils, _;
    _ = require('underscore');
    Backbone = require('backbone');
    support = require('chaplin/lib/support');
    utils = require('chaplin/lib/utils');
    mediator = {};
    mediator.subscribe = Backbone.Events.on;
    mediator.unsubscribe = Backbone.Events.off;
    mediator.publish = Backbone.Events.trigger;
    mediator.on = mediator.subscribe;
    mediator._callbacks = null;
    utils.readonly(mediator, 'subscribe', 'unsubscribe', 'publish', 'on');
    mediator.seal = function() {
      if (support.propertyDescriptors && Object.seal) {
        return Object.seal(mediator);
      }
    };
    utils.readonly(mediator, 'seal');
    return module.exports = mediator;
  }
});

require.define({
  'chaplin/dispatcher': function(exports, require, module) {
    var Backbone, Dispatcher, EventBroker, utils, _;
    _ = require('underscore');
    Backbone = require('backbone');
    utils = require('chaplin/lib/utils');
    EventBroker = require('chaplin/lib/event_broker');
    return module.exports = Dispatcher = (function() {

      Dispatcher.extend = Backbone.Model.extend;

      _(Dispatcher.prototype).extend(EventBroker);

      Dispatcher.prototype.previousControllerName = null;

      Dispatcher.prototype.currentControllerName = null;

      Dispatcher.prototype.currentController = null;

      Dispatcher.prototype.currentAction = null;

      Dispatcher.prototype.currentParams = null;

      Dispatcher.prototype.url = null;

      function Dispatcher() {
        this.initialize.apply(this, arguments);
      }

      Dispatcher.prototype.initialize = function(options) {
        if (options == null) {
          options = {};
        }
        this.settings = _(options).defaults({
          controllerPath: 'controllers/',
          controllerSuffix: '_controller'
        });
        this.subscribeEvent('matchRoute', this.matchRoute);
        return this.subscribeEvent('!startupController', this.startupController);
      };

      Dispatcher.prototype.matchRoute = function(route, params) {
        return this.startupController(route.controller, route.action, params);
      };

      Dispatcher.prototype.startupController = function(controllerName, action, params) {
        var handler, isSameController;
        if (action == null) {
          action = 'index';
        }
        if (params == null) {
          params = {};
        }
        if (params.changeURL !== false) {
          params.changeURL = true;
        }
        if (params.forceStartup !== true) {
          params.forceStartup = false;
        }
        isSameController = !params.forceStartup && this.currentControllerName === controllerName && this.currentAction === action && (!this.currentParams || _(params).isEqual(this.currentParams));
        if (isSameController) {
          return;
        }
        handler = _(this.controllerLoaded).bind(this, controllerName, action, params);
        return this.loadController(controllerName, handler);
      };

      Dispatcher.prototype.loadController = function(controllerName, handler) {
        var controllerFileName, path;
        controllerFileName = utils.underscorize(controllerName) + this.settings.controllerSuffix;
        path = this.settings.controllerPath + controllerFileName;
        if (typeof define !== "undefined" && define !== null ? define.amd : void 0) {
          return require([path], handler);
        } else {
          return handler(require(path));
        }
      };

      Dispatcher.prototype.controllerLoaded = function(controllerName, action, params, ControllerConstructor) {
        var controller, currentController, currentControllerName;
        currentControllerName = this.currentControllerName || null;
        currentController = this.currentController || null;
        if (currentController) {
          this.publishEvent('beforeControllerDispose', currentController);
          currentController.dispose(params, controllerName);
        }
        controller = new ControllerConstructor(params, currentControllerName);
        controller[action](params, currentControllerName);
        if (controller.redirected) {
          return;
        }
        this.previousControllerName = currentControllerName;
        this.currentControllerName = controllerName;
        this.currentController = controller;
        this.currentAction = action;
        this.currentParams = params;
        this.adjustURL(controller, params);
        return this.publishEvent('startupController', {
          previousControllerName: this.previousControllerName,
          controller: this.currentController,
          controllerName: this.currentControllerName,
          params: this.currentParams
        });
      };

      Dispatcher.prototype.adjustURL = function(controller, params) {
        var url;
        if (params.path || params.path === '') {
          url = params.path;
        } else if (typeof controller.historyURL === 'function') {
          url = controller.historyURL(params);
        } else if (typeof controller.historyURL === 'string') {
          url = controller.historyURL;
        } else {
          throw new Error('Dispatcher#adjustURL: controller for ' + ("" + this.currentControllerName + " does not provide a historyURL"));
        }
        if (params.changeURL) {
          this.publishEvent('!router:changeURL', url);
        }
        return this.url = url;
      };

      Dispatcher.prototype.disposed = false;

      Dispatcher.prototype.dispose = function() {
        if (this.disposed) {
          return;
        }
        this.unsubscribeAllEvents();
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Dispatcher;

    })();
  }
});

require.define({
  'chaplin/controllers/controller': function(exports, require, module) {
    var Backbone, Controller, EventBroker, _;
    _ = require('underscore');
    Backbone = require('backbone');
    EventBroker = require('chaplin/lib/event_broker');
    return module.exports = Controller = (function() {

      Controller.extend = Backbone.Model.extend;

      _(Controller.prototype).extend(EventBroker);

      Controller.prototype.view = null;

      Controller.prototype.currentId = null;

      Controller.prototype.redirected = false;

      function Controller() {
        this.initialize.apply(this, arguments);
      }

      Controller.prototype.initialize = function() {};

      Controller.prototype.redirectTo = function(arg1, action, params) {
        this.redirected = true;
        if (arguments.length === 1) {
          return this.publishEvent('!router:route', arg1, function(routed) {
            if (!routed) {
              throw new Error('Controller#redirectTo: no route matched');
            }
          });
        } else {
          return this.publishEvent('!startupController', arg1, action, params);
        }
      };

      Controller.prototype.disposed = false;

      Controller.prototype.dispose = function() {
        var obj, prop, properties, _i, _len;
        if (this.disposed) {
          return;
        }
        for (prop in this) {
          if (!__hasProp.call(this, prop)) continue;
          obj = this[prop];
          if (obj && typeof obj.dispose === 'function') {
            obj.dispose();
            delete this[prop];
          }
        }
        this.unsubscribeAllEvents();
        properties = ['currentId', 'redirected'];
        for (_i = 0, _len = properties.length; _i < _len; _i++) {
          prop = properties[_i];
          delete this[prop];
        }
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Controller;

    })();
  }
});

require.define({
  'chaplin/models/collection': function(exports, require, module) {
    var Backbone, Collection, EventBroker, Model, _;
    _ = require('underscore');
    Backbone = require('backbone');
    EventBroker = require('chaplin/lib/event_broker');
    Model = require('chaplin/models/model');
    return module.exports = Collection = (function(_super) {

      __extends(Collection, _super);

      function Collection() {
        return Collection.__super__.constructor.apply(this, arguments);
      }

      _(Collection.prototype).extend(EventBroker);

      Collection.prototype.model = Model;

      Collection.prototype.initDeferred = function() {
        return _(this).extend($.Deferred());
      };

      Collection.prototype.serialize = function() {
        var model, _i, _len, _ref, _results;
        _ref = this.models;
        _results = [];
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          model = _ref[_i];
          if (model instanceof Model) {
            _results.push(model.serialize());
          } else {
            _results.push(model.toJSON());
          }
        }
        return _results;
      };

      Collection.prototype.addAtomic = function(models, options) {
        var direction, model;
        if (options == null) {
          options = {};
        }
        if (!models.length) {
          return;
        }
        options.silent = true;
        direction = typeof options.at === 'number' ? 'pop' : 'shift';
        while (model = models[direction]()) {
          this.add(model, options);
        }
        return this.trigger('reset');
      };

      Collection.prototype.update = function(models, options) {
        var fingerPrint, i, ids, model, newFingerPrint, preexistent, _i, _ids, _len;
        if (options == null) {
          options = {};
        }
        fingerPrint = this.pluck('id').join();
        ids = _(models).pluck('id');
        newFingerPrint = ids.join();
        if (newFingerPrint !== fingerPrint) {
          _ids = _(ids);
          i = this.models.length;
          while (i--) {
            model = this.models[i];
            if (!_ids.include(model.id)) {
              this.remove(model);
            }
          }
        }
        if (newFingerPrint !== fingerPrint || options.deep) {
          for (i = _i = 0, _len = models.length; _i < _len; i = ++_i) {
            model = models[i];
            preexistent = this.get(model.id);
            if (preexistent) {
              if (options.deep) {
                preexistent.set(model);
              }
            } else {
              this.add(model, {
                at: i
              });
            }
          }
        }
      };

      Collection.prototype.disposed = false;

      Collection.prototype.dispose = function() {
        var prop, properties, _i, _len;
        if (this.disposed) {
          return;
        }
        this.trigger('dispose', this);
        this.reset([], {
          silent: true
        });
        this.unsubscribeAllEvents();
        this.off();
        if (typeof this.reject === "function") {
          this.reject();
        }
        properties = ['model', 'models', '_byId', '_byCid', '_callbacks'];
        for (_i = 0, _len = properties.length; _i < _len; _i++) {
          prop = properties[_i];
          delete this[prop];
        }
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Collection;

    })(Backbone.Collection);
  }
});

require.define({
  'chaplin/models/model': function(exports, require, module) {
    var Backbone, EventBroker, Model, utils, _;
    _ = require('underscore');
    Backbone = require('backbone');
    utils = require('chaplin/lib/utils');
    EventBroker = require('chaplin/lib/event_broker');
    return module.exports = Model = (function(_super) {
      var serializeAttributes;

      __extends(Model, _super);

      function Model() {
        return Model.__super__.constructor.apply(this, arguments);
      }

      _(Model.prototype).extend(EventBroker);

      Model.prototype.initDeferred = function() {
        return _(this).extend($.Deferred());
      };

      Model.prototype.getAttributes = function() {
        return this.attributes;
      };

      serializeAttributes = function(model, attributes, modelStack) {
        var delegator, item, key, value;
        if (!modelStack) {
          delegator = utils.beget(attributes);
          modelStack = [model];
        } else {
          modelStack.push(model);
        }
        for (key in attributes) {
          value = attributes[key];
          if (value instanceof Backbone.Model) {
            if (delegator == null) {
              delegator = utils.beget(attributes);
            }
            delegator[key] = value === model || __indexOf.call(modelStack, value) >= 0 ? null : serializeAttributes(value, value.getAttributes(), modelStack);
          } else if (value instanceof Backbone.Collection) {
            if (delegator == null) {
              delegator = utils.beget(attributes);
            }
            delegator[key] = (function() {
              var _i, _len, _ref, _results;
              _ref = value.models;
              _results = [];
              for (_i = 0, _len = _ref.length; _i < _len; _i++) {
                item = _ref[_i];
                _results.push(serializeAttributes(item, item.getAttributes(), modelStack));
              }
              return _results;
            })();
          }
        }
        modelStack.pop();
        return delegator || attributes;
      };

      Model.prototype.serialize = function() {
        return serializeAttributes(this, this.getAttributes());
      };

      Model.prototype.disposed = false;

      Model.prototype.dispose = function() {
        var prop, properties, _i, _len;
        if (this.disposed) {
          return;
        }
        this.trigger('dispose', this);
        this.unsubscribeAllEvents();
        this.off();
        if (typeof this.reject === "function") {
          this.reject();
        }
        properties = ['collection', 'attributes', 'changed', '_escapedAttributes', '_previousAttributes', '_silent', '_pending', '_callbacks'];
        for (_i = 0, _len = properties.length; _i < _len; _i++) {
          prop = properties[_i];
          delete this[prop];
        }
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Model;

    })(Backbone.Model);
  }
});

require.define({
  'chaplin/views/layout': function(exports, require, module) {
    var $, Backbone, EventBroker, Layout, utils, _;
    $ = require('jquery');
    _ = require('underscore');
    Backbone = require('backbone');
    utils = require('chaplin/lib/utils');
    EventBroker = require('chaplin/lib/event_broker');
    return module.exports = Layout = (function() {

      Layout.extend = Backbone.Model.extend;

      _(Layout.prototype).extend(EventBroker);

      Layout.prototype.title = '';

      Layout.prototype.events = {};

      Layout.prototype.el = document;

      Layout.prototype.$el = $(document);

      Layout.prototype.cid = 'chaplin-layout';

      function Layout() {
        this.openLink = __bind(this.openLink, this);
        this.initialize.apply(this, arguments);
      }

      Layout.prototype.initialize = function(options) {
        if (options == null) {
          options = {};
        }
        this.title = options.title;
        this.settings = _(options).defaults({
          titleTemplate: _.template("<%= subtitle %> \u2013 <%= title %>"),
          openExternalToBlank: false,
          routeLinks: 'a, .go-to',
          skipRouting: '.noscript',
          scrollTo: [0, 0]
        });
        this.subscribeEvent('beforeControllerDispose', this.hideOldView);
        this.subscribeEvent('startupController', this.showNewView);
        this.subscribeEvent('startupController', this.adjustTitle);
        if (this.settings.routeLinks) {
          this.startLinkRouting();
        }
        return this.delegateEvents();
      };

      Layout.prototype.delegateEvents = Backbone.View.prototype.delegateEvents;

      Layout.prototype.undelegateEvents = Backbone.View.prototype.undelegateEvents;

      Layout.prototype.hideOldView = function(controller) {
        var scrollTo, view;
        scrollTo = this.settings.scrollTo;
        if (scrollTo) {
          window.scrollTo(scrollTo[0], scrollTo[1]);
        }
        view = controller.view;
        if (view) {
          return view.$el.css('display', 'none');
        }
      };

      Layout.prototype.showNewView = function(context) {
        var view;
        view = context.controller.view;
        if (view) {
          return view.$el.css({
            display: 'block',
            opacity: 1,
            visibility: 'visible'
          });
        }
      };

      Layout.prototype.adjustTitle = function(context) {
        var subtitle, title;
        title = this.title || '';
        subtitle = context.controller.title || '';
        title = this.settings.titleTemplate({
          title: title,
          subtitle: subtitle
        });
        return setTimeout((function() {
          return document.title = title;
        }), 50);
      };

      Layout.prototype.startLinkRouting = function() {
        if (this.settings.routeLinks) {
          return $(document).on('click', this.settings.routeLinks, this.openLink);
        }
      };

      Layout.prototype.stopLinkRouting = function() {
        if (this.settings.routeLinks) {
          return $(document).off('click', this.settings.routeLinks);
        }
      };

      Layout.prototype.openLink = function(event) {
        var $el, el, href, internal, isAnchor, path, skipRouting, type, _ref, _ref1;
        if (utils.modifierKeyPressed(event)) {
          return;
        }
        el = event.currentTarget;
        $el = $(el);
        isAnchor = el.nodeName === 'A';
        href = $el.attr('href') || $el.data('href') || null;
        if (href === null || href === void 0 || href === '' || href.charAt(0) === '#') {
          return;
        }
        if (isAnchor && ($el.attr('target') === '_blank' || $el.attr('rel') === 'external' || ((_ref = el.protocol) !== 'http:' && _ref !== 'https:' && _ref !== 'file:'))) {
          return;
        }
        skipRouting = this.settings.skipRouting;
        type = typeof skipRouting;
        if (type === 'function' && !skipRouting(href, el) || type === 'string' && $el.is(skipRouting)) {
          return;
        }
        internal = !isAnchor || ((_ref1 = el.hostname) === location.hostname || _ref1 === '');
        if (!internal) {
          if (this.settings.openExternalToBlank) {
            event.preventDefault();
            window.open(el.href);
          }
          return;
        }
        if (isAnchor) {
          path = el.pathname + el.search;
          if (path.charAt(0) !== '/') {
            path = "/" + path;
          }
        } else {
          path = href;
        }
        this.publishEvent('!router:route', path, function(routed) {
          if (routed) {
            event.preventDefault();
          } else if (!isAnchor) {
            location.href = path;
          }
        });
      };

      Layout.prototype.disposed = false;

      Layout.prototype.dispose = function() {
        if (this.disposed) {
          return;
        }
        this.stopLinkRouting();
        this.unsubscribeAllEvents();
        this.undelegateEvents();
        delete this.title;
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Layout;

    })();
  }
});

require.define({
  'chaplin/views/view': function(exports, require, module) {
    var $, Backbone, Collection, EventBroker, Model, View, utils, _;
    $ = require('jquery');
    _ = require('underscore');
    Backbone = require('backbone');
    utils = require('chaplin/lib/utils');
    EventBroker = require('chaplin/lib/event_broker');
    Model = require('chaplin/models/model');
    Collection = require('chaplin/models/collection');
    return module.exports = View = (function(_super) {

      __extends(View, _super);

      _(View.prototype).extend(EventBroker);

      View.prototype.autoRender = false;

      View.prototype.container = null;

      View.prototype.containerMethod = 'append';

      View.prototype.subviews = null;

      View.prototype.subviewsByName = null;

      View.prototype.wrapMethod = function(name) {
        var func, instance;
        instance = this;
        func = instance[name];
        instance["" + name + "IsWrapped"] = true;
        return instance[name] = function() {
          if (this.disposed) {
            return false;
          }
          func.apply(instance, arguments);
          instance["after" + (utils.upcase(name))].apply(instance, arguments);
          return instance;
        };
      };

      function View() {
        if (this.initialize !== View.prototype.initialize) {
          this.wrapMethod('initialize');
        }
        if (this.render !== View.prototype.render) {
          this.wrapMethod('render');
        } else {
          this.render = _(this.render).bind(this);
        }
        View.__super__.constructor.apply(this, arguments);
      }

      View.prototype.initialize = function(options) {
        var prop, _i, _len, _ref;
        if (options) {
          _ref = ['autoRender', 'container', 'containerMethod'];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            prop = _ref[_i];
            if (options[prop] != null) {
              this[prop] = options[prop];
            }
          }
        }
        this.subviews = [];
        this.subviewsByName = {};
        if (this.model || this.collection) {
          this.modelBind('dispose', this.dispose);
        }
        if (!this.initializeIsWrapped) {
          return this.afterInitialize();
        }
      };

      View.prototype.afterInitialize = function() {
        if (this.autoRender) {
          return this.render();
        }
      };

      View.prototype.delegate = function(eventType, second, third) {
        var event, events, handler, list, selector;
        if (typeof eventType !== 'string') {
          throw new TypeError('View#delegate: first argument must be a string');
        }
        if (arguments.length === 2) {
          handler = second;
        } else if (arguments.length === 3) {
          selector = second;
          if (typeof selector !== 'string') {
            throw new TypeError('View#delegate: ' + 'second argument must be a string');
          }
          handler = third;
        } else {
          throw new TypeError('View#delegate: ' + 'only two or three arguments are allowed');
        }
        if (typeof handler !== 'function') {
          throw new TypeError('View#delegate: ' + 'handler argument must be function');
        }
        list = (function() {
          var _i, _len, _ref, _results;
          _ref = eventType.split(' ');
          _results = [];
          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
            event = _ref[_i];
            _results.push("" + event + ".delegate" + this.cid);
          }
          return _results;
        }).call(this);
        events = list.join(' ');
        handler = _(handler).bind(this);
        if (selector) {
          this.$el.on(events, selector, handler);
        } else {
          this.$el.on(events, handler);
        }
        return handler;
      };

      View.prototype.undelegate = function() {
        return this.$el.unbind(".delegate" + this.cid);
      };

      View.prototype.modelBind = function(type, handler) {
        var modelOrCollection;
        if (typeof type !== 'string') {
          throw new TypeError('View#modelBind: ' + 'type must be a string');
        }
        if (typeof handler !== 'function') {
          throw new TypeError('View#modelBind: ' + 'handler argument must be function');
        }
        modelOrCollection = this.model || this.collection;
        if (!modelOrCollection) {
          throw new TypeError('View#modelBind: no model or collection set');
        }
        modelOrCollection.off(type, handler, this);
        return modelOrCollection.on(type, handler, this);
      };

      View.prototype.modelUnbind = function(type, handler) {
        var modelOrCollection;
        if (typeof type !== 'string') {
          throw new TypeError('View#modelUnbind: ' + 'type argument must be a string');
        }
        if (typeof handler !== 'function') {
          throw new TypeError('View#modelUnbind: ' + 'handler argument must be a function');
        }
        modelOrCollection = this.model || this.collection;
        if (!modelOrCollection) {
          return;
        }
        return modelOrCollection.off(type, handler);
      };

      View.prototype.modelUnbindAll = function() {
        var modelOrCollection;
        modelOrCollection = this.model || this.collection;
        if (!modelOrCollection) {
          return;
        }
        return modelOrCollection.off(null, null, this);
      };

      View.prototype.pass = function(attribute, selector) {
        var _this = this;
        return this.modelBind("change:" + attribute, function(model, value) {
          var $el;
          $el = _this.$(selector);
          if ($el.is('input, textarea, select, button')) {
            return $el.val(value);
          } else {
            return $el.text(value);
          }
        });
      };

      View.prototype.subview = function(name, view) {
        if (name && view) {
          this.removeSubview(name);
          this.subviews.push(view);
          this.subviewsByName[name] = view;
          return view;
        } else if (name) {
          return this.subviewsByName[name];
        }
      };

      View.prototype.removeSubview = function(nameOrView) {
        var index, name, otherName, otherView, view, _ref;
        if (!nameOrView) {
          return;
        }
        if (typeof nameOrView === 'string') {
          name = nameOrView;
          view = this.subviewsByName[name];
        } else {
          view = nameOrView;
          _ref = this.subviewsByName;
          for (otherName in _ref) {
            otherView = _ref[otherName];
            if (view === otherView) {
              name = otherName;
              break;
            }
          }
        }
        if (!(name && view && view.dispose)) {
          return;
        }
        view.dispose();
        index = _(this.subviews).indexOf(view);
        if (index > -1) {
          this.subviews.splice(index, 1);
        }
        return delete this.subviewsByName[name];
      };

      View.prototype.getTemplateData = function() {
        var items, model, modelOrCollection, templateData, _i, _len, _ref;
        if (this.model) {
          templateData = this.model instanceof Model ? this.model.serialize() : utils.beget(this.model.attributes);
        } else if (this.collection) {
          if (this.collection instanceof Collection) {
            items = this.collection.serialize();
          } else {
            items = [];
            _ref = this.collection.models;
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              model = _ref[_i];
              items.push(utils.beget(model.attributes));
            }
          }
          templateData = {
            items: items
          };
        } else {
          templateData = {};
        }
        modelOrCollection = this.model || this.collection;
        if (modelOrCollection) {
          if (typeof modelOrCollection.state === 'function' && !('resolved' in templateData)) {
            templateData.resolved = modelOrCollection.state() === 'resolved';
          }
          if (typeof modelOrCollection.isSynced === 'function' && !('synced' in templateData)) {
            templateData.synced = modelOrCollection.isSynced();
          }
        }
        return templateData;
      };

      View.prototype.getTemplateFunction = function() {
        throw new Error('View#getTemplateFunction must be overridden');
      };

      View.prototype.render = function() {
        var html, templateFunc;
        if (this.disposed) {
          return false;
        }
        templateFunc = this.getTemplateFunction();
        if (typeof templateFunc === 'function') {
          html = templateFunc(this.getTemplateData());
          this.$el.empty().append(html);
        }
        if (!this.renderIsWrapped) {
          this.afterRender();
        }
        return this;
      };

      View.prototype.afterRender = function() {
        if (this.container) {
          $(this.container)[this.containerMethod](this.el);
          return this.trigger('addedToDOM');
        }
      };

      View.prototype.disposed = false;

      View.prototype.dispose = function() {
        var prop, properties, subview, _i, _j, _len, _len1, _ref;
        if (this.disposed) {
          return;
        }
        _ref = this.subviews;
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          subview = _ref[_i];
          subview.dispose();
        }
        this.unsubscribeAllEvents();
        this.modelUnbindAll();
        this.off();
        this.$el.remove();
        properties = ['el', '$el', 'options', 'model', 'collection', 'subviews', 'subviewsByName', '_callbacks'];
        for (_j = 0, _len1 = properties.length; _j < _len1; _j++) {
          prop = properties[_j];
          delete this[prop];
        }
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return View;

    })(Backbone.View);
  }
});

require.define({
  'chaplin/views/collection_view': function(exports, require, module) {
    var $, CollectionView, View, _;
    $ = require('jquery');
    _ = require('underscore');
    View = require('chaplin/views/view');
    return module.exports = CollectionView = (function(_super) {

      __extends(CollectionView, _super);

      function CollectionView() {
        this.renderAllItems = __bind(this.renderAllItems, this);

        this.showHideFallback = __bind(this.showHideFallback, this);

        this.itemsResetted = __bind(this.itemsResetted, this);

        this.itemRemoved = __bind(this.itemRemoved, this);

        this.itemAdded = __bind(this.itemAdded, this);
        return CollectionView.__super__.constructor.apply(this, arguments);
      }

      CollectionView.prototype.itemView = null;

      CollectionView.prototype.autoRender = true;

      CollectionView.prototype.renderItems = true;

      CollectionView.prototype.animationDuration = 500;

      CollectionView.prototype.useCssAnimation = false;

      CollectionView.prototype.listSelector = null;

      CollectionView.prototype.$list = null;

      CollectionView.prototype.fallbackSelector = null;

      CollectionView.prototype.$fallback = null;

      CollectionView.prototype.loadingSelector = null;

      CollectionView.prototype.$loading = null;

      CollectionView.prototype.itemSelector = null;

      CollectionView.prototype.filterer = null;

      CollectionView.prototype.filterCallback = function(view, included) {
        var display;
        display = included ? '' : 'none';
        return view.$el.stop(true, true).css('display', display);
      };

      CollectionView.prototype.visibleItems = null;

      CollectionView.prototype.initialize = function(options) {
        if (options == null) {
          options = {};
        }
        CollectionView.__super__.initialize.apply(this, arguments);
        this.visibleItems = [];
        this.addCollectionListeners();
        if (options.renderItems != null) {
          this.renderItems = options.renderItems;
        }
        if (options.itemView != null) {
          this.itemView = options.itemView;
        }
        if (options.filterer != null) {
          return this.filter(options.filterer);
        }
      };

      CollectionView.prototype.addCollectionListeners = function() {
        this.modelBind('add', this.itemAdded);
        this.modelBind('remove', this.itemRemoved);
        return this.modelBind('reset', this.itemsResetted);
      };

      CollectionView.prototype.getTemplateFunction = function() {};

      CollectionView.prototype.render = function() {
        CollectionView.__super__.render.apply(this, arguments);
        this.$list = this.listSelector ? this.$(this.listSelector) : this.$el;
        this.initFallback();
        this.initLoadingIndicator();
        if (this.renderItems) {
          return this.renderAllItems();
        }
      };

      CollectionView.prototype.itemAdded = function(item, collection, options) {
        if (options == null) {
          options = {};
        }
        return this.renderAndInsertItem(item, options.index);
      };

      CollectionView.prototype.itemRemoved = function(item) {
        return this.removeViewForItem(item);
      };

      CollectionView.prototype.itemsResetted = function() {
        return this.renderAllItems();
      };

      CollectionView.prototype.initFallback = function() {
        if (!this.fallbackSelector) {
          return;
        }
        this.$fallback = this.$(this.fallbackSelector);
        this.on('visibilityChange', this.showHideFallback);
        this.modelBind('syncStateChange', this.showHideFallback);
        return this.showHideFallback();
      };

      CollectionView.prototype.showHideFallback = function() {
        var visible;
        visible = this.visibleItems.length === 0 && (typeof this.collection.isSynced === 'function' ? this.collection.isSynced() : true);
        return this.$fallback.css('display', visible ? 'block' : 'none');
      };

      CollectionView.prototype.initLoadingIndicator = function() {
        if (!(this.loadingSelector && typeof this.collection.isSyncing === 'function')) {
          return;
        }
        this.$loading = this.$(this.loadingSelector);
        this.modelBind('syncStateChange', this.showHideLoadingIndicator);
        return this.showHideLoadingIndicator();
      };

      CollectionView.prototype.showHideLoadingIndicator = function() {
        var visible;
        visible = this.collection.length === 0 && this.collection.isSyncing();
        return this.$loading.css('display', visible ? 'block' : 'none');
      };

      CollectionView.prototype.getItemViews = function() {
        var itemViews, name, view, _ref;
        itemViews = {};
        _ref = this.subviewsByName;
        for (name in _ref) {
          view = _ref[name];
          if (name.slice(0, 9) === 'itemView:') {
            itemViews[name.slice(9)] = view;
          }
        }
        return itemViews;
      };

      CollectionView.prototype.filter = function(filterer, filterCallback) {
        var included, index, item, view, _i, _len, _ref;
        this.filterer = filterer;
        if (filterCallback) {
          this.filterCallback = filterCallback;
        }
        if (filterCallback == null) {
          filterCallback = this.filterCallback;
        }
        if (!_(this.getItemViews()).isEmpty()) {
          _ref = this.collection.models;
          for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
            item = _ref[index];
            included = typeof filterer === 'function' ? filterer(item, index) : true;
            view = this.subview("itemView:" + item.cid);
            if (!view) {
              throw new Error('CollectionView#filter: ' + ("no view found for " + item.cid));
            }
            this.filterCallback(view, included);
            this.updateVisibleItems(view.model, included, false);
          }
        }
        return this.trigger('visibilityChange', this.visibleItems);
      };

      CollectionView.prototype.renderAllItems = function() {
        var cid, index, item, items, remainingViewsByCid, view, _i, _j, _len, _len1, _ref;
        items = this.collection.models;
        this.visibleItems = [];
        remainingViewsByCid = {};
        for (_i = 0, _len = items.length; _i < _len; _i++) {
          item = items[_i];
          view = this.subview("itemView:" + item.cid);
          if (view) {
            remainingViewsByCid[item.cid] = view;
          }
        }
        _ref = this.getItemViews();
        for (cid in _ref) {
          if (!__hasProp.call(_ref, cid)) continue;
          view = _ref[cid];
          if (!(cid in remainingViewsByCid)) {
            this.removeSubview("itemView:" + cid);
          }
        }
        for (index = _j = 0, _len1 = items.length; _j < _len1; index = ++_j) {
          item = items[index];
          view = this.subview("itemView:" + item.cid);
          if (view) {
            this.insertView(item, view, index, false);
          } else {
            this.renderAndInsertItem(item, index);
          }
        }
        if (!items.length) {
          return this.trigger('visibilityChange', this.visibleItems);
        }
      };

      CollectionView.prototype.renderAndInsertItem = function(item, index) {
        var view;
        view = this.renderItem(item);
        return this.insertView(item, view, index);
      };

      CollectionView.prototype.renderItem = function(item) {
        var view;
        view = this.subview("itemView:" + item.cid);
        if (!view) {
          view = this.getView(item);
          this.subview("itemView:" + item.cid, view);
        }
        view.render();
        return view;
      };

      CollectionView.prototype.getView = function(model) {
        if (this.itemView) {
          return new this.itemView({
            model: model
          });
        } else {
          throw new Error('The CollectionView#itemView property ' + 'must be defined or the getView() must be overridden.');
        }
      };

      CollectionView.prototype.insertView = function(item, view, index, enableAnimation) {
        var $list, $next, $previous, $viewEl, children, included, length, position, viewEl,
          _this = this;
        if (index == null) {
          index = null;
        }
        if (enableAnimation == null) {
          enableAnimation = true;
        }
        position = typeof index === 'number' ? index : this.collection.indexOf(item);
        included = typeof this.filterer === 'function' ? this.filterer(item, position) : true;
        viewEl = view.el;
        $viewEl = view.$el;
        if (included) {
          if (enableAnimation) {
            if (this.useCssAnimation) {
              $viewEl.addClass('animated-item-view');
            } else {
              $viewEl.css('opacity', 0);
            }
          }
        } else {
          this.filterCallback(view, included);
        }
        $list = this.$list;
        children = this.itemSelector ? $list.children(this.itemSelector) : $list.children();
        if (children.get(position) !== viewEl) {
          length = children.length;
          if (length === 0 || position === length) {
            $list.append(viewEl);
          } else {
            if (position === 0) {
              $next = children.eq(position);
              $next.before(viewEl);
            } else {
              $previous = children.eq(position - 1);
              $previous.after(viewEl);
            }
          }
        }
        view.trigger('addedToDOM');
        this.updateVisibleItems(item, included);
        if (enableAnimation && included) {
          if (this.useCssAnimation) {
            setTimeout(function() {
              return $viewEl.addClass('animated-item-view-end');
            }, 0);
          } else {
            $viewEl.animate({
              opacity: 1
            }, this.animationDuration);
          }
        }
      };

      CollectionView.prototype.removeViewForItem = function(item) {
        this.updateVisibleItems(item, false);
        return this.removeSubview("itemView:" + item.cid);
      };

      CollectionView.prototype.updateVisibleItems = function(item, includedInFilter, triggerEvent) {
        var includedInVisibleItems, visibilityChanged, visibleItemsIndex;
        if (triggerEvent == null) {
          triggerEvent = true;
        }
        visibilityChanged = false;
        visibleItemsIndex = _(this.visibleItems).indexOf(item);
        includedInVisibleItems = visibleItemsIndex > -1;
        if (includedInFilter && !includedInVisibleItems) {
          this.visibleItems.push(item);
          visibilityChanged = true;
        } else if (!includedInFilter && includedInVisibleItems) {
          this.visibleItems.splice(visibleItemsIndex, 1);
          visibilityChanged = true;
        }
        if (visibilityChanged && triggerEvent) {
          this.trigger('visibilityChange', this.visibleItems);
        }
        return visibilityChanged;
      };

      CollectionView.prototype.dispose = function() {
        var prop, properties, _i, _len;
        if (this.disposed) {
          return;
        }
        properties = ['$list', '$fallback', '$loading', 'visibleItems'];
        for (_i = 0, _len = properties.length; _i < _len; _i++) {
          prop = properties[_i];
          delete this[prop];
        }
        return CollectionView.__super__.dispose.apply(this, arguments);
      };

      return CollectionView;

    })(View);
  }
});

require.define({
  'chaplin/lib/route': function(exports, require, module) {
    var Backbone, Controller, EventBroker, Route, _;
    _ = require('underscore');
    Backbone = require('backbone');
    EventBroker = require('chaplin/lib/event_broker');
    Controller = require('chaplin/controllers/controller');
    return module.exports = Route = (function() {
      var escapeRegExp, queryStringFieldSeparator, queryStringValueSeparator, reservedParams;

      Route.extend = Backbone.Model.extend;

      _(Route.prototype).extend(EventBroker);

      reservedParams = ['path', 'changeURL'];

      escapeRegExp = /[-[\]{}()+?.,\\^$|#\s]/g;

      queryStringFieldSeparator = '&';

      queryStringValueSeparator = '=';

      function Route(pattern, target, options) {
        var _ref;
        this.options = options != null ? options : {};
        this.handler = __bind(this.handler, this);

        this.addParamName = __bind(this.addParamName, this);

        this.pattern = pattern;
        _ref = target.split('#'), this.controller = _ref[0], this.action = _ref[1];
        if (_(Controller.prototype).has(this.action)) {
          throw new Error('Route: You should not use existing controller properties as action names');
        }
        this.createRegExp();
      }

      Route.prototype.createRegExp = function() {
        var pattern;
        if (_.isRegExp(this.pattern)) {
          this.regExp = this.pattern;
          return;
        }
        pattern = this.pattern.replace(escapeRegExp, '\\$&').replace(/(?::|\*)(\w+)/g, this.addParamName);
        return this.regExp = RegExp("^" + pattern + "(?=\\?|$)");
      };

      Route.prototype.addParamName = function(match, paramName) {
        var _ref;
        if ((_ref = this.paramNames) == null) {
          this.paramNames = [];
        }
        if (_(reservedParams).include(paramName)) {
          throw new Error("Route#addParamName: parameter name " + paramName + " is reserved");
        }
        this.paramNames.push(paramName);
        if (match.charAt(0) === ':') {
          return '([^\/\?]+)';
        } else {
          return '(.*?)';
        }
      };

      Route.prototype.test = function(path) {
        var constraint, constraints, matched, name, params;
        matched = this.regExp.test(path);
        if (!matched) {
          return false;
        }
        constraints = this.options.constraints;
        if (constraints) {
          params = this.extractParams(path);
          for (name in constraints) {
            if (!__hasProp.call(constraints, name)) continue;
            constraint = constraints[name];
            if (!constraint.test(params[name])) {
              return false;
            }
          }
        }
        return true;
      };

      Route.prototype.handler = function(path, options) {
        var params;
        params = this.buildParams(path, options);
        return this.publishEvent('matchRoute', this, params);
      };

      Route.prototype.buildParams = function(path, options) {
        var params, patternParams, queryParams;
        params = {};
        queryParams = this.extractQueryParams(path);
        _(params).extend(queryParams);
        patternParams = this.extractParams(path);
        _(params).extend(patternParams);
        _(params).extend(this.options.params);
        params.changeURL = Boolean(options && options.changeURL);
        params.path = path;
        return params;
      };

      Route.prototype.extractParams = function(path) {
        var index, match, matches, paramName, params, _i, _len, _ref;
        params = {};
        matches = this.regExp.exec(path);
        _ref = matches.slice(1);
        for (index = _i = 0, _len = _ref.length; _i < _len; index = ++_i) {
          match = _ref[index];
          paramName = this.paramNames ? this.paramNames[index] : index;
          params[paramName] = match;
        }
        return params;
      };

      Route.prototype.extractQueryParams = function(path) {
        var current, field, matches, pair, pairs, params, queryString, regExp, value, _i, _len, _ref;
        params = {};
        regExp = /\?(.+?)(?=#|$)/;
        matches = regExp.exec(path);
        if (!matches) {
          return params;
        }
        queryString = matches[1];
        pairs = queryString.split(queryStringFieldSeparator);
        for (_i = 0, _len = pairs.length; _i < _len; _i++) {
          pair = pairs[_i];
          if (!pair.length) {
            continue;
          }
          _ref = pair.split(queryStringValueSeparator), field = _ref[0], value = _ref[1];
          if (!field.length) {
            continue;
          }
          field = decodeURIComponent(field);
          value = decodeURIComponent(value);
          current = params[field];
          if (current) {
            if (current.push) {
              current.push(value);
            } else {
              params[field] = [current, value];
            }
          } else {
            params[field] = value;
          }
        }
        return params;
      };

      return Route;

    })();
  }
});

require.define({
  'chaplin/lib/router': function(exports, require, module) {
    var Backbone, EventBroker, Route, Router, mediator, _;
    _ = require('underscore');
    Backbone = require('backbone');
    mediator = require('chaplin/mediator');
    EventBroker = require('chaplin/lib/event_broker');
    Route = require('chaplin/lib/route');
    return module.exports = Router = (function() {

      Router.extend = Backbone.Model.extend;

      _(Router.prototype).extend(EventBroker);

      function Router(options) {
        this.options = options != null ? options : {};
        this.route = __bind(this.route, this);

        this.match = __bind(this.match, this);

        _(this.options).defaults({
          pushState: true
        });
        this.subscribeEvent('!router:route', this.routeHandler);
        this.subscribeEvent('!router:changeURL', this.changeURLHandler);
        this.createHistory();
      }

      Router.prototype.createHistory = function() {
        return Backbone.history || (Backbone.history = new Backbone.History());
      };

      Router.prototype.startHistory = function() {
        return Backbone.history.start(this.options);
      };

      Router.prototype.stopHistory = function() {
        if (Backbone.History.started) {
          return Backbone.history.stop();
        }
      };

      Router.prototype.match = function(pattern, target, options) {
        var route;
        if (options == null) {
          options = {};
        }
        route = new Route(pattern, target, options);
        Backbone.history.handlers.push({
          route: route,
          callback: route.handler
        });
        return route;
      };

      Router.prototype.route = function(path) {
        var handler, _i, _len, _ref;
        path = path.replace(/^(\/#|\/)/, '');
        _ref = Backbone.history.handlers;
        for (_i = 0, _len = _ref.length; _i < _len; _i++) {
          handler = _ref[_i];
          if (handler.route.test(path)) {
            handler.callback(path, {
              changeURL: true
            });
            return true;
          }
        }
        return false;
      };

      Router.prototype.routeHandler = function(path, callback) {
        var routed;
        routed = this.route(path);
        return typeof callback === "function" ? callback(routed) : void 0;
      };

      Router.prototype.changeURL = function(url) {
        return Backbone.history.navigate(url, {
          trigger: false
        });
      };

      Router.prototype.changeURLHandler = function(url) {
        return this.changeURL(url);
      };

      Router.prototype.disposed = false;

      Router.prototype.dispose = function() {
        if (this.disposed) {
          return;
        }
        this.stopHistory();
        delete Backbone.history;
        this.unsubscribeAllEvents();
        this.disposed = true;
        return typeof Object.freeze === "function" ? Object.freeze(this) : void 0;
      };

      return Router;

    })();
  }
});

require.define({
  'chaplin/lib/delayer': function(exports, require, module) {
    var Delayer;
    Delayer = {
      setTimeout: function(name, time, handler) {
        var handle, wrappedHandler, _ref,
          _this = this;
        if ((_ref = this.timeouts) == null) {
          this.timeouts = {};
        }
        this.clearTimeout(name);
        wrappedHandler = function() {
          delete _this.timeouts[name];
          return handler();
        };
        handle = setTimeout(wrappedHandler, time);
        this.timeouts[name] = handle;
        return handle;
      },
      clearTimeout: function(name) {
        if (!(this.timeouts && (this.timeouts[name] != null))) {
          return;
        }
        clearTimeout(this.timeouts[name]);
        delete this.timeouts[name];
      },
      clearAllTimeouts: function() {
        var handle, name, _ref;
        if (!this.timeouts) {
          return;
        }
        _ref = this.timeouts;
        for (name in _ref) {
          handle = _ref[name];
          this.clearTimeout(name);
        }
      },
      setInterval: function(name, time, handler) {
        var handle, _ref;
        this.clearInterval(name);
        if ((_ref = this.intervals) == null) {
          this.intervals = {};
        }
        handle = setInterval(handler, time);
        this.intervals[name] = handle;
        return handle;
      },
      clearInterval: function(name) {
        if (!(this.intervals && this.intervals[name])) {
          return;
        }
        clearInterval(this.intervals[name]);
        delete this.intervals[name];
      },
      clearAllIntervals: function() {
        var handle, name, _ref;
        if (!this.intervals) {
          return;
        }
        _ref = this.intervals;
        for (name in _ref) {
          handle = _ref[name];
          this.clearInterval(name);
        }
      },
      clearDelayed: function() {
        this.clearAllTimeouts();
        this.clearAllIntervals();
      }
    };
    if (typeof Object.freeze === "function") {
      Object.freeze(Delayer);
    }
    return module.exports = Delayer;
  }
});

require.define({
  'chaplin/lib/event_broker': function(exports, require, module) {
    var EventBroker, mediator;
    mediator = require('chaplin/mediator');
    EventBroker = {
      subscribeEvent: function(type, handler) {
        if (typeof type !== 'string') {
          throw new TypeError('EventBroker#subscribeEvent: ' + 'type argument must be a string');
        }
        if (typeof handler !== 'function') {
          throw new TypeError('EventBroker#subscribeEvent: ' + 'handler argument must be a function');
        }
        mediator.unsubscribe(type, handler, this);
        return mediator.subscribe(type, handler, this);
      },
      unsubscribeEvent: function(type, handler) {
        if (typeof type !== 'string') {
          throw new TypeError('EventBroker#unsubscribeEvent: ' + 'type argument must be a string');
        }
        if (typeof handler !== 'function') {
          throw new TypeError('EventBroker#unsubscribeEvent: ' + 'handler argument must be a function');
        }
        return mediator.unsubscribe(type, handler);
      },
      unsubscribeAllEvents: function() {
        return mediator.unsubscribe(null, null, this);
      },
      publishEvent: function() {
        var args, type;
        type = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
        if (typeof type !== 'string') {
          throw new TypeError('EventBroker#publishEvent: ' + 'type argument must be a string');
        }
        return mediator.publish.apply(mediator, [type].concat(__slice.call(args)));
      }
    };
    if (typeof Object.freeze === "function") {
      Object.freeze(EventBroker);
    }
    return module.exports = EventBroker;
  }
});

require.define({
  'chaplin/lib/support': function(exports, require, module) {
    var support;
    support = {
      propertyDescriptors: (function() {
        var o;
        if (!(typeof Object.defineProperty === 'function' && typeof Object.defineProperties === 'function')) {
          return false;
        }
        try {
          o = {};
          Object.defineProperty(o, 'foo', {
            value: 'bar'
          });
          return o.foo === 'bar';
        } catch (error) {
          return false;
        }
      })()
    };
    return module.exports = support;
  }
});

require.define({
  'chaplin/lib/sync_machine': function(exports, require, module) {
    var STATE_CHANGE, SYNCED, SYNCING, SyncMachine, UNSYNCED, event, _fn, _i, _len, _ref;
    UNSYNCED = 'unsynced';
    SYNCING = 'syncing';
    SYNCED = 'synced';
    STATE_CHANGE = 'syncStateChange';
    SyncMachine = {
      _syncState: UNSYNCED,
      _previousSyncState: null,
      syncState: function() {
        return this._syncState;
      },
      isUnsynced: function() {
        return this._syncState === UNSYNCED;
      },
      isSynced: function() {
        return this._syncState === SYNCED;
      },
      isSyncing: function() {
        return this._syncState === SYNCING;
      },
      unsync: function() {
        var _ref;
        if ((_ref = this._syncState) === SYNCING || _ref === SYNCED) {
          this._previousSync = this._syncState;
          this._syncState = UNSYNCED;
          this.trigger(this._syncState, this, this._syncState);
          this.trigger(STATE_CHANGE, this, this._syncState);
        }
      },
      beginSync: function() {
        var _ref;
        if ((_ref = this._syncState) === UNSYNCED || _ref === SYNCED) {
          this._previousSync = this._syncState;
          this._syncState = SYNCING;
          this.trigger(this._syncState, this, this._syncState);
          this.trigger(STATE_CHANGE, this, this._syncState);
        }
      },
      finishSync: function() {
        if (this._syncState === SYNCING) {
          this._previousSync = this._syncState;
          this._syncState = SYNCED;
          this.trigger(this._syncState, this, this._syncState);
          this.trigger(STATE_CHANGE, this, this._syncState);
        }
      },
      abortSync: function() {
        if (this._syncState === SYNCING) {
          this._syncState = this._previousSync;
          this._previousSync = this._syncState;
          this.trigger(this._syncState, this, this._syncState);
          this.trigger(STATE_CHANGE, this, this._syncState);
        }
      }
    };
    _ref = [UNSYNCED, SYNCING, SYNCED, STATE_CHANGE];
    _fn = function(event) {
      return SyncMachine[event] = function(callback, context) {
        if (context == null) {
          context = this;
        }
        this.on(event, callback, context);
        if (this._syncState === event) {
          return callback.call(context);
        }
      };
    };
    for (_i = 0, _len = _ref.length; _i < _len; _i++) {
      event = _ref[_i];
      _fn(event);
    }
    if (typeof Object.freeze === "function") {
      Object.freeze(SyncMachine);
    }
    return module.exports = SyncMachine;
  }
});

require.define({
  'chaplin/lib/utils': function(exports, require, module) {
    var support, utils;
    support = require('chaplin/lib/support');
    utils = {
      beget: (function() {
        var ctor;
        if (typeof Object.create === 'function') {
          return Object.create;
        } else {
          ctor = function() {};
          return function(obj) {
            ctor.prototype = obj;
            return new ctor;
          };
        }
      })(),
      readonly: (function() {
        var readonlyDescriptor;
        if (support.propertyDescriptors) {
          readonlyDescriptor = {
            writable: false,
            enumerable: true,
            configurable: false
          };
          return function() {
            var obj, prop, properties, _i, _len;
            obj = arguments[0], properties = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
            for (_i = 0, _len = properties.length; _i < _len; _i++) {
              prop = properties[_i];
              readonlyDescriptor.value = obj[prop];
              Object.defineProperty(obj, prop, readonlyDescriptor);
            }
            return true;
          };
        } else {
          return function() {
            return false;
          };
        }
      })(),
      upcase: function(str) {
        return str.charAt(0).toUpperCase() + str.substring(1);
      },
      underscorize: function(string) {
        return string.replace(/[A-Z]/g, function(char, index) {
          return (index !== 0 ? '_' : '') + char.toLowerCase();
        });
      },
      modifierKeyPressed: function(event) {
        return event.shiftKey || event.altKey || event.ctrlKey || event.metaKey;
      }
    };
    if (typeof Object.seal === "function") {
      Object.seal(utils);
    }
    return module.exports = utils;
  }
});

require.define({
  'chaplin': function(exports, require, module) {
    var Application, Collection, CollectionView, Controller, Delayer, Dispatcher, EventBroker, Layout, Model, Route, Router, SyncMachine, View, mediator, support, utils;
    Application = require('chaplin/application');
    mediator = require('chaplin/mediator');
    Dispatcher = require('chaplin/dispatcher');
    Controller = require('chaplin/controllers/controller');
    Collection = require('chaplin/models/collection');
    Model = require('chaplin/models/model');
    Layout = require('chaplin/views/layout');
    View = require('chaplin/views/view');
    CollectionView = require('chaplin/views/collection_view');
    Route = require('chaplin/lib/route');
    Router = require('chaplin/lib/router');
    Delayer = require('chaplin/lib/delayer');
    EventBroker = require('chaplin/lib/event_broker');
    support = require('chaplin/lib/support');
    SyncMachine = require('chaplin/lib/sync_machine');
    utils = require('chaplin/lib/utils');
    return module.exports = {
      Application: Application,
      mediator: mediator,
      Dispatcher: Dispatcher,
      Controller: Controller,
      Collection: Collection,
      Model: Model,
      Layout: Layout,
      View: View,
      CollectionView: CollectionView,
      Route: Route,
      Router: Router,
      Delayer: Delayer,
      EventBroker: EventBroker,
      support: support,
      SyncMachine: SyncMachine,
      utils: utils
    };
  }
});
;

