diff --git a/changelog.md b/changelog.md new file mode 100644 index 0000000..d59c4e7 --- /dev/null +++ b/changelog.md @@ -0,0 +1,15 @@ +### v1.1.0 [view commit logs](https://github.com/BedeGaming/orchestra/compare/v1.0.0...v1.1.0) + +#### Features + +* Added Backbone-routing. +* Added Backbone.Storage. +* Added Backbone.Service. + +#### Misc + +* Bumped Backbone dependency to 1.2.3 + +### v1.0.0 + +* Initial release. \ No newline at end of file diff --git a/dist/orchestra.js b/dist/orchestra.js index b1f729f..226df98 100644 --- a/dist/orchestra.js +++ b/dist/orchestra.js @@ -21,6 +21,8 @@ var _backbone = require('backbone'); var _backbone2 = _interopRequireDefault(_backbone); +var _backboneRouting = require('backbone-routing'); + var _backboneCocktail = require('backbone.cocktail'); var _backboneCocktail2 = _interopRequireDefault(_backboneCocktail); @@ -29,6 +31,14 @@ var _backboneRadio = require('backbone.radio'); var _backboneRadio2 = _interopRequireDefault(_backboneRadio); +var _backboneService = require('backbone.service'); + +var _backboneService2 = _interopRequireDefault(_backboneService); + +var _backboneStorage = require('backbone.storage'); + +var _backboneStorage2 = _interopRequireDefault(_backboneStorage); + var _mvcCollection = require('./mvc/collection'); var _mvcCollection2 = _interopRequireDefault(_mvcCollection); @@ -83,7 +93,11 @@ _lodash2['default'].extend(Orchestra, { _: _lodash2['default'], $: _jquery2['default'], Radio: _backboneRadio2['default'], + Service: _backboneService2['default'], + Storage: _backboneStorage2['default'], Cocktail: _backboneCocktail2['default'], + Route: _backboneRouting.Route, + Router: _backboneRouting.Router, Collection: _mvcCollection2['default'], Currency: _helpersCurrency2['default'], LocalStorage: _helpersLocalStorage2['default'], @@ -115,7 +129,747 @@ _lodash2['default'].extend(Orchestra, { exports['default'] = Orchestra; module.exports = exports['default']; -},{"./helpers/currency":26,"./helpers/handlebars":27,"./helpers/localStorage":28,"./helpers/module":29,"./helpers/translate":30,"./helpers/visibility":31,"./mixins/touch.view":32,"./mvc/collection":33,"backbone":11,"backbone.cocktail":2,"backbone.marionette":4,"backbone.radio":8,"backbone.stickit":10,"jquery":22,"lodash":23}],2:[function(require,module,exports){ +},{"./helpers/currency":37,"./helpers/handlebars":38,"./helpers/localStorage":39,"./helpers/module":40,"./helpers/translate":41,"./helpers/visibility":42,"./mixins/touch.view":43,"./mvc/collection":44,"backbone":21,"backbone-routing":2,"backbone.cocktail":4,"backbone.marionette":6,"backbone.radio":10,"backbone.service":12,"backbone.stickit":18,"backbone.storage":19,"jquery":33,"lodash":34}],2:[function(require,module,exports){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('backbone'), require('backbone-metal')) : typeof define === 'function' && define.amd ? define(['backbone', 'backbone-metal'], factory) : global.Backbone.Routing = factory(global.Backbone, global.Metal); +})(this, function (Backbone, Metal) { + 'use strict'; + + var CancellationError = Metal.Error.extend({ + name: 'CancellationError' + }); + + /** + * @public + * @class Route + */ + var Route = Metal.Class.extend({ + + /** + * @public + * @method enter + * @returns {Promise} + * @param {...*} [args=[]] + */ + enter: function enter() { + var _this = this; + + var args = arguments[0] === undefined ? [] : arguments[0]; + + this._isEntering = true; + this.trigger.apply(this, ['before:enter before:fetch', this].concat(args)); + + return Promise.resolve().then(function () { + if (_this._isCancelled) { + return Promise.reject(new CancellationError()); + } + return _this.fetch.apply(_this, args); + }).then(function () { + return _this.trigger.apply(_this, ['fetch before:render', _this].concat(args)); + }).then(function () { + if (_this._isCancelled) { + return Promise.reject(new CancellationError()); + } + return _this.render.apply(_this, args); + }).then(function () { + _this._isEntering = false; + _this.trigger.apply(_this, ['render enter', _this].concat(args)); + })['catch'](function (err) { + _this._isEntering = false; + if (err instanceof CancellationError) { + _this.trigger('cancel', _this); + } else { + _this.trigger('error error:enter', _this, err); + throw err; + } + }); + }, + + /** + * @public + * @method exit + * @returns {Promise} + */ + exit: function exit() { + var _this2 = this; + + if (this._isEntering) { + this.cancel(); + } + this._isExiting = true; + this.trigger('before:exit before:destroy', this); + + return Promise.resolve().then(function () { + return _this2.destroy(); + }).then(function () { + _this2._isExiting = false; + _this2.trigger('destroy exit', _this2); + _this2.stopListening(); + })['catch'](function (err) { + _this2._isExiting = false; + _this2.trigger('error error:exit', _this2, err); + _this2.stopListening(); + throw err; + }); + }, + + /** + * @public + * @method cancel + * @returns {Promise} + */ + cancel: function cancel() { + var _this3 = this; + + if (!this._isEntering) { + return; + } + this.trigger('before:cancel', this); + this._isCancelled = true; + return new Promise(function (resolve, reject) { + _this3.once('cancel', resolve); + _this3.once('enter error', reject); + }); + }, + + /** + * @public + * @method isEntering + * @returns {Boolean} + */ + isEntering: function isEntering() { + return !!this._isEntering; + }, + + /** + * @public + * @method isExiting + * @returns {Boolean} + */ + isExiting: function isExiting() { + return !!this._isExiting; + }, + + /** + * @public + * @method isCancelled + * @returns {Boolean} + */ + isCancelled: function isCancelled() { + return !!this._isCancelled; + }, + + /** + * @public + * @abstract + * @method fetch + * @param {...*} [args=[]] + */ + fetch: function fetch() {}, + + /** + * @public + * @abstract + * @method render + * @param {...*} [args=[]] + */ + render: function render() {}, + + /** + * @public + * @abstract + * @method destroy + */ + destroy: function destroy() {} + }); + + /** + * @public + * @class Router + */ + var Router = Metal.Class.extend(Backbone.Router.prototype, Backbone.Router).extend({ + constructor: function constructor() { + this.listenTo(Backbone.history, 'route', this._onHistoryRoute); + this._super.apply(this, arguments); + }, + + /** + * @public + * @method isActive + * @returns {Boolean} + */ + isActive: function isActive() { + return !!this._isActive; + }, + + /** + * @public + * @method execute + * @param {Function} callback + * @param {Array} [args] + */ + execute: function execute(callback, args) { + var _this4 = this; + + var wasInactive = !this._isActive; + if (wasInactive) { + this.trigger('before:enter', this); + } + + this.trigger('before:route', this); + + return Promise.resolve().then(function () { + return _this4._execute(callback, args); + }).then(function () { + _this4.trigger('route', _this4); + + if (wasInactive) { + _this4.trigger('enter', _this4); + } + })['catch'](function (err) { + _this4.trigger('error', _this4, err); + Backbone.history.trigger('error', _this4, err); + throw err; + }); + }, + + /** + * @public + * @method execute + * @param {Function} callback + * @param {Array} [args] + * @returns {Promise} + */ + _execute: function _execute(callback, args) { + var _this5 = this; + + return Promise.resolve().then(function () { + if (Router._prevRoute instanceof Route) { + return Router._prevRoute.exit(); + } + }).then(function () { + var route = Router._prevRoute = callback.apply(_this5, args); + if (route instanceof Route) { + route.router = _this5; + return route.enter(args); + } + }); + }, + + /** + * @private + * @method _onHistoryRoute + * @param {Router} router + */ + _onHistoryRoute: function _onHistoryRoute(router) { + this._isActive = router === this; + } + }, { + + /** + * @private + * @member _prevRoute + */ + _prevRoute: null + }); + + var backbone_routing = { Route: Route, Router: Router, CancellationError: CancellationError }; + + return backbone_routing; +}); +//# sourceMappingURL=./backbone-routing.js.map +},{"backbone":21,"backbone-metal":3}],3:[function(require,module,exports){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('underscore'), require('backbone')) : + typeof define === 'function' && define.amd ? define(['underscore', 'backbone'], factory) : + global.Metal = factory(global._, global.Backbone) +}(this, function (_, Backbone) { 'use strict'; + + var Metal = Backbone.Metal = {}; + + /** + * Wraps the passed method so that `this._super` will point to the superMethod + * when the method is invoked. + * + * @private + * @method wrap + * @param {Function} method - The method to call. + * @param {Function} superMeqthod - The super method. + * @return {Function} - wrapped function. + */ + function _wrap(method, superMethod) { + return function () { + var prevSuper = this._super; + this._super = superMethod; + var ret = method.apply(this, arguments); + this._super = prevSuper; + return ret; + }; + } + + /** + * A reference to safe regex for checking if a function calls `_super`. + * + * @private + * @const {RegExp} + */ + var CONTAINS_SUPER = /xyz/.test(new Function("xyz")) ? /\b_super\b/ : /.*/; + + /** + * Assigns properties of source object to destination object, wrapping methods + * that call their super method. + * + * @private + * @method wrapAll + * @param {Object} dest - The destination object. + * @param {Object} source - The source object. + */ + function _wrapAll(dest, source) { + var keys = _.keys(source), + length = keys.length, + i, + name, + method, + superMethod, + hasSuper; + + for (i = 0; i < length; i++) { + name = keys[i]; + method = source[name]; + superMethod = dest[name]; + + // Test if new method calls `_super` + hasSuper = CONTAINS_SUPER.test(method); + + // Only wrap the new method if the original method was a function and the + // new method calls `_super`. + if (hasSuper && _.isFunction(method) && _.isFunction(superMethod)) { + dest[name] = _wrap(method, superMethod); + + // Otherwise just add the new method or property to the object. + } else { + dest[name] = method; + } + } + } + + /** + * Creates a new Class. + * + * ```js + * var MyClass = Class.extend({ + * initialize() { + * console.log('Created!'); + * } + * }); + * + * new MyClass(); + * // >> Created! + * ``` + * + * @public + * @class Class + * @memberOf Metal + * @memberOf Backbone + */ + var Class = Metal.Class = function () { + var _ref; + (_ref = this).initialize.apply(_ref, arguments); + }; + + /** + * An overridable method called when objects are instantiated. Does not do + * anything by default. + * + * @public + * @abstract + * @method initialize + */ + Class.prototype.initialize = _.noop; + + _.extend(Class, { + + /** + * Creates a new subclass. + * + * ```js + * var MyClass = Class.extend({ + * // ... + * }); + * + * var myClass = new MyClass(); + * myClass instanceof MyClass + * // true + * myClass instanceof Class + * // true + * ``` + * + * @public + * @static + * @method extend + * @param {Object} [protoProps] - The properties to be added to the prototype. + * @param {Object} [staticProps] - The properties to be added to the constructor. + */ + extend: function extend(protoProps, staticProps) { + var Parent = this; + 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 || !_.has(protoProps, "constructor")) { + Child = function () { + Parent.apply(this, arguments); + }; + } else if (CONTAINS_SUPER.test(protoProps.constructor)) { + Child = _wrap(protoProps.constructor, Parent.prototype.constructor); + } else { + Child = protoProps.constructor; + } + + // Add static properties to the constructor function, if supplied. + _.extend(Child, Parent); + if (staticProps) { + _wrapAll(Child, staticProps); + } + + // Set the prototype chain to inherit from `parent`, without calling + // `parent`'s constructor function. + var Surrogate = function () { + this.constructor = Child; + }; + Surrogate.prototype = Parent.prototype; + Child.prototype = new Surrogate(); + + // Add prototype properties (instance properties) to the subclass, + // if supplied. + if (protoProps) { + _wrapAll(Child.prototype, protoProps); + } + + // Set a convenience property in case the parent class is needed later. + Child.superclass = Parent; + + // Set a convenience property in case the parent's prototype is needed + // later. + Child.__super__ = Parent.prototype; + + return Child; + }, + + /** + * Mixes properties onto the class's prototype. + * + * ```js + * var MyMixin = new Mixin({ + * alert() { + * console.log('Alert!'); + * } + * }); + * + * var MyClass = Class.extend({ + * initialize() { + * this.alert(); + * } + * }); + * + * MyClass.mixin(MyMixin); + * + * new MyClass(); + * // >> Alert! + * ``` + * + * @public + * @static + * @method mixin + * @param {Object} protoProps - The properties to be added to the prototype. + * @return {Class} - The class. + */ + mixin: function mixin(protoProps) { + // Add prototype properties (instance properties) to the class, if supplied. + _wrapAll(this.prototype, protoProps); + return this; + }, + + /** + * Mixes properties onto the class's constructor. + * + * ```js + * var MyMixin = new Mixin({ + * alert() { + * console.log('Alert!'); + * } + * }); + * + * var MyClass = Class.extend(...); + * + * MyClass.include(MyMixin); + * + * MyClass.alert(); + * // >> Alert! + * ``` + * + * You can also simply pass a plain javascript object. + * + * ```js + * var MyClass = Class.extend(...); + * + * MyClass.include({ + * alert() { + * console.log('Alert!'); + * } + * }); + * + * MyClass.alert(); + * // >> Alert! + * ``` + * + * @public + * @static + * @method mixin + * @param {Object} staticProps - The properties to be added to the constructor. + * @return {Class} - The class. + */ + include: function include(staticProps) { + // Add static properties to the constructor function, if supplied. + _wrapAll(this, staticProps); + return this; + }, + + /** + * Checks if `value` is a Metal Class. + * + * ```js + * _.isClass(Class.extend(...)); + * // >> true + * _.isClass(new Class()); + * // >> true + * _.isClass(function() {...}); + * // >> false + * _.isClass({...}); + * // >> false + * ``` + * @public + * @method isClass + * @memberOf _ + * @param {*} value - The value to check. + */ + isClass: function isClass(value) { + return !!value && (value instanceof Class || value.prototype instanceof Class || value === Class); + } + }); + + /** + * Allows you to create mixins, whose properties can be added to other classes. + * + * @public + * @class Mixin + * @memberOf Metal + * @memberOf Backbone + * @param {Object} protoProps - The properties to be added to the prototype. + */ + var Mixin = Metal.Mixin = function (protoProps) { + // Add prototype properties (instance properties) to the class, if supplied. + _.extend(this, protoProps); + }; + + /** + * Checks if `value` is a Metal Mixin. + * + * ```js + * _.isMixin(new Mixin()); + * // >> true + * _.isMixin({}); + * // >> false + * _.isMixin(function() {...}); + * // >> false + * _.isMixin(new Class()); + * // >> false + * ``` + * + * @public + * @method isMixin + * @memberOf _ + * @param {*} value - The value to check. + */ + Mixin.isMixin = function (value) { + return !!value && value instanceof Mixin; + }; + + /** + * @private + * @const {String[]} + */ + var ERROR_PROPS = ["description", "fileName", "lineNumber", "name", "message", "number"]; + + /** + * A subclass of the JavaScript Error. + * + * ```js + * throw new Metal.Error('Oh you\'ve really done it now...'); + * // Uncaught Metal.Error: Oh you've really done it now... + * // [stack trace] + * ``` + * + * @class Error + * @memberOf Metal + * @extends Error + * @uses Metal.Class + */ + var Err = Metal.Error = Class.extend.call(Error, { + + /** + * @public + * @constructs Error + * @param {String} [message] - A description of the error. + * @param {Object} [options] - Settings for the error. + * @param {String} [options.message] - A description of the error. + */ + constructor: function constructor(message) { + var options = arguments[1] === undefined ? {} : arguments[1]; + // If options are provided in place of a message, assume message exists on + // options. + if (_.isObject(message)) { + options = message; + message = options.message; + } + + // Create a fake error with message in order to capture a stack trace. + var error = Error.call(this, message); + + // Copy over all the error-related properties. + _.extend(this, _.pick(error, ERROR_PROPS), _.pick(options, ERROR_PROPS)); + + // Adds a `stack` property to the given error object that will yield the + // stack trace at the time captureStackTrace was called. + // When collecting the stack trace all frames above the topmost call + // to this function, including that call, will be left out of the + // stack trace. + // This is useful because we can hide Metal implementation details + // that are not very helpful for the user. + Err.captureStackTrace(this, Err); + }, + + /** + * Formats the error message to display in the console. + * + * @public + * @method toString + * @returns {String} - Formatted error message. + */ + toString: function toString() { + return "" + this.name + ": " + this.message; + } + }, { + + /** + * A safe reference to V8's `Error.captureStackTrace`. + * + * @public + * @method captureStackTrace + */ + captureStackTrace: function captureStackTrace(target, method) { + if (Error.captureStackTrace) { + Error.captureStackTrace(target, method); + } + } + }); + + /** + * @class Error + * @mixes Class + */ + _.extend(Err, Class); + + /** + * Display a deprecation warning with the provided message. + * + * @public + * @method deprecate + * @param {String|Object} message - A description of the deprecation. + * @param {String} message.prev - The deprecated item. + * @param {String} message.next - The replacement for the deprecated item. + * @param {Boolean} [test] - An optional boolean. If falsy, the deprecation will be displayed. + */ + var deprecate = Metal.deprecate = function (message, test) { + // Returns if test is provided and is falsy. + if (test !== undefined && test) { + return; + } + + // If message is provided as an object, format the object into a string. + if (_.isObject(message)) { + message = deprecate._format(message.prev, message.next); + } + + // Ensure that message is a string + message = message && message.toString(); + + // If deprecation message has not already been warned, send the warning. + if (!deprecate._cache[message]) { + deprecate._warn("Deprecation warning: " + message); + deprecate._cache[message] = true; + } + }; + + /** + * Format a message for deprecate. + * + * @private + * @method _format + * @memberOf deprecate + * @param {String} prev - The deprecated item. + * @param {String} next - The replacement for the deprecated item. + * @return {String} - The formatted message. + */ + deprecate._format = function (prev, next) { + return "" + prev + " is going to be removed in the future. Please use " + next + " instead."; + }; + + /** + * A safe reference to `console.warn` that will fallback to `console.log` or + * `_noop` if the `console` object does not exist. + * + * @private + * @method _warn + * @memberOf deprecate + * @param {*...} - The values to warn in the console. + */ + deprecate._warn = typeof console !== "undefined" && (console.warn || console.log) || _.noop; + + /** + * An internal cache to avoid sending the same deprecation warning multiple + * times. + * + * @private + * @property _cache + * @memberOf deprecate + */ + deprecate._cache = {}; + + /** + * A `Metal.Mixin` version of `Backbone.Events`. + * + * @mixin Events + * @memberOf Metal + * @memberOf Backbone + * @extends Metal.Mixin + * @mixes Backbone.Events + */ + var Events = Metal.Events = new Mixin(Backbone.Events); + + /** + * @class Class + * @mixes Events + */ + Class.mixin(Events); + + + return Metal; + +})); +//# sourceMappingURL=./backbone-metal.js.map +},{"backbone":21,"underscore":36}],4:[function(require,module,exports){ // (c) 2012 Onsi Fakhouri // Cocktail.js may be freely distributed under the MIT license. // http://github.com/onsi/cocktail @@ -219,7 +973,7 @@ module.exports = exports['default']; return Cocktail; })); -},{"underscore":3}],3:[function(require,module,exports){ +},{"underscore":5}],5:[function(require,module,exports){ // Underscore.js 1.5.2 // http://underscorejs.org // (c) 2009-2013 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors @@ -1497,7 +2251,7 @@ module.exports = exports['default']; }).call(this); -},{}],4:[function(require,module,exports){ +},{}],6:[function(require,module,exports){ // MarionetteJS (Backbone.Marionette) // ---------------------------------- // v2.4.3 @@ -4992,7 +5746,7 @@ module.exports = exports['default']; return Marionette; })); -},{"backbone":11,"backbone.babysitter":5,"backbone.wreqr":6,"underscore":7}],5:[function(require,module,exports){ +},{"backbone":21,"backbone.babysitter":7,"backbone.wreqr":8,"underscore":9}],7:[function(require,module,exports){ // Backbone.BabySitter // ------------------- // v0.1.10 @@ -5184,7 +5938,7 @@ module.exports = exports['default']; })); -},{"backbone":11,"underscore":7}],6:[function(require,module,exports){ +},{"backbone":21,"underscore":9}],8:[function(require,module,exports){ // Backbone.Wreqr (Backbone.Marionette) // ---------------------------------- // v1.3.5 @@ -5621,7 +6375,7 @@ module.exports = exports['default']; })); -},{"backbone":11,"underscore":7}],7:[function(require,module,exports){ +},{"backbone":21,"underscore":9}],9:[function(require,module,exports){ // Underscore.js 1.8.3 // http://underscorejs.org // (c) 2009-2015 Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors @@ -7171,7 +7925,7 @@ module.exports = exports['default']; } }.call(this)); -},{}],8:[function(require,module,exports){ +},{}],10:[function(require,module,exports){ // Backbone.Radio v1.0.2 (function (global, factory) { typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory(require("underscore"), require("backbone")) : typeof define === "function" && define.amd ? define(["underscore", "backbone"], factory) : global.Backbone.Radio = factory(global._, global.Backbone); @@ -7508,9 +8262,1509 @@ module.exports = exports['default']; return backbone_radio; }); //# sourceMappingURL=./backbone.radio.js.map -},{"backbone":11,"underscore":9}],9:[function(require,module,exports){ -arguments[4][7][0].apply(exports,arguments) -},{"dup":7}],10:[function(require,module,exports){ +},{"backbone":21,"underscore":11}],11:[function(require,module,exports){ +arguments[4][9][0].apply(exports,arguments) +},{"dup":9}],12:[function(require,module,exports){ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('backbone-metal-classify'), require('backbone-normalize-hash'), require('backbone.radio'), require('underscore'), require('es6-promise')) : typeof define === 'function' && define.amd ? define(['backbone-metal-classify', 'backbone-normalize-hash', 'backbone.radio', 'underscore', 'es6-promise'], factory) : global.Backbone.Service = factory(global.classify, global.normalizeHash, global.Radio, global._, global.PromisePolyfill); +})(this, function (classify, normalizeHash, Radio, _, PromisePolyfill) { + 'use strict'; + + var resolved = PromisePolyfill.Promise.resolve(); + + Radio.Channel = classify(Radio.Channel); + + /** + * @class Service + */ + var backbone_service = Radio.Channel.extend({ + /** + * @constructs Service + */ + constructor: function constructor() { + var _this = this; + + var start = _.once(function () { + return resolved.then(function () { + return _this.start(); + }); + }); + var requests = normalizeHash(this, 'requests'); + + _.each(requests, function (val, key) { + _this.reply(key, function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return start().then(function () { + return _this[key].apply(_this, args); + })['catch'](function (err) { + _this.onError(err); + throw err; + }); + }); + }); + + this._super.apply(this, arguments); + }, + + /** + * @abstract + * @method setup + */ + setup: function setup() {}, + + /** + * @abstract + * @method start + */ + start: function start() {}, + + /** + * @abstract + * @method onError + */ + onError: function onError() {} + }); + + return backbone_service; +}); +//# sourceMappingURL=./backbone.service.js.map +},{"backbone-metal-classify":13,"backbone-normalize-hash":15,"backbone.radio":16,"es6-promise":17,"underscore":36}],13:[function(require,module,exports){ +var Metal = require('backbone-metal'); +var _ = require('underscore'); + +module.exports = function classify(target) { + if (target.prototype instanceof Metal.Class) { + return target; + } + + return Metal.Class.extend( + _.extend({ constructor: target }, + _.omit(target.prototype, _.keys(Metal.Class.prototype)) + ), + _.omit(target, _.keys(Metal.Class)) + ); +}; + +},{"backbone-metal":14,"underscore":36}],14:[function(require,module,exports){ +arguments[4][3][0].apply(exports,arguments) +},{"backbone":21,"dup":3,"underscore":36}],15:[function(require,module,exports){ +var _ = require('underscore'); + +module.exports = function normalizeHash(source, hash) { + var obj = _.result(source, hash); + var clone = {}; + + _.each(obj, function(val, key) { + clone[key] = _.isFunction(val) ? val : source[key]; + }); + + return clone; +}; + +},{"underscore":36}],16:[function(require,module,exports){ +// Backbone.Radio v0.9.1 +(function (global, factory) { + typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory(require("underscore"), require("backbone")) : typeof define === "function" && define.amd ? define(["underscore", "backbone"], factory) : global.Backbone.Radio = factory(global._, global.Backbone); +})(this, function (_, Backbone) { + "use strict"; + + var previousRadio = Backbone.Radio; + + var Radio = Backbone.Radio = {}; + + Radio.VERSION = "0.9.1"; + + // This allows you to run multiple instances of Radio on the same + // webapp. After loading the new version, call `noConflict()` to + // get a reference to it. At the same time the old version will be + // returned to Backbone.Radio. + Radio.noConflict = function () { + Backbone.Radio = previousRadio; + return this; + }; + + // Whether or not we're in DEBUG mode or not. DEBUG mode helps you + // get around the issues of lack of warnings when events are mis-typed. + Radio.DEBUG = false; + + // Format debug text. + Radio._debugText = function (warning, eventName, channelName) { + return warning + (channelName ? " on the " + channelName + " channel" : "") + ": \"" + eventName + "\""; + }; + + // This is the method that's called when an unregistered event was called. + // By default, it logs warning to the console. By overriding this you could + // make it throw an Error, for instance. This would make firing a nonexistent event + // have the same consequence as firing a nonexistent method on an Object. + Radio.debugLog = function (warning, eventName, channelName) { + if (Radio.DEBUG && console && console.warn) { + console.warn(Radio._debugText(warning, eventName, channelName)); + } + }; + + var eventSplitter = /\s+/; + + // An internal method used to handle Radio's method overloading for Requests and + // Commands. It's borrowed from Backbone.Events. It differs from Backbone's overload + // API (which is used in Backbone.Events) in that it doesn't support space-separated + // event names. + Radio._eventsApi = function (obj, action, name, rest) { + if (!name) { + return false; + } + + var results = {}; + + // Handle event maps. + if (typeof name === "object") { + for (var key in name) { + var result = obj[action].apply(obj, [key, name[key]].concat(rest)); + eventSplitter.test(key) ? _.extend(results, result) : results[key] = result; + } + return results; + } + + // Handle space separated event names. + if (eventSplitter.test(name)) { + var names = name.split(eventSplitter); + for (var i = 0, l = names.length; i < l; i++) { + results[names[i]] = obj[action].apply(obj, [names[i]].concat(rest)); + } + return results; + } + + return false; + }; + + // An optimized way to execute callbacks. + Radio._callHandler = function (callback, context, args) { + var a1 = args[0], + a2 = args[1], + a3 = args[2]; + switch (args.length) { + case 0: + return callback.call(context); + case 1: + return callback.call(context, a1); + case 2: + return callback.call(context, a1, a2); + case 3: + return callback.call(context, a1, a2, a3); + default: + return callback.apply(context, args); + } + }; + + // A helper used by `off` methods to the handler from the store + function removeHandler(store, name, callback, context) { + var event = store[name]; + if ((!callback || (callback === event.callback || callback === event.callback._callback)) && (!context || context === event.context)) { + delete store[name]; + return true; + } + } + + function removeHandlers(store, name, callback, context) { + store || (store = {}); + var names = name ? [name] : _.keys(store); + var matched = false; + + for (var i = 0, length = names.length; i < length; i++) { + name = names[i]; + + // If there's no event by this name, log it and continue + // with the loop + if (!store[name]) { + continue; + } + + if (removeHandler(store, name, callback, context)) { + matched = true; + } + } + + return matched; + } + + /* + * tune-in + * ------- + * Get console logs of a channel's activity + * + */ + + var _logs = {}; + + // This is to produce an identical function in both tuneIn and tuneOut, + // so that Backbone.Events unregisters it. + function _partial(channelName) { + return _logs[channelName] || (_logs[channelName] = _.partial(Radio.log, channelName)); + } + + _.extend(Radio, { + + // Log information about the channel and event + log: function log(channelName, eventName) { + var args = _.rest(arguments, 2); + console.log("[" + channelName + "] \"" + eventName + "\"", args); + }, + + // Logs all events on this channel to the console. It sets an + // internal value on the channel telling it we're listening, + // then sets a listener on the Backbone.Events + tuneIn: function tuneIn(channelName) { + var channel = Radio.channel(channelName); + channel._tunedIn = true; + channel.on("all", _partial(channelName)); + return this; + }, + + // Stop logging all of the activities on this channel to the console + tuneOut: function tuneOut(channelName) { + var channel = Radio.channel(channelName); + channel._tunedIn = false; + channel.off("all", _partial(channelName)); + delete _logs[channelName]; + return this; + } + }); + + /* + * Backbone.Radio.Commands + * ----------------------- + * A messaging system for sending orders. + * + */ + + Radio.Commands = { + + // Issue a command + command: function command(name) { + var args = _.rest(arguments); + if (Radio._eventsApi(this, "command", name, args)) { + return this; + } + var channelName = this.channelName; + var commands = this._commands; + + // Check if we should log the command, and if so, do it + if (channelName && this._tunedIn) { + Radio.log.apply(this, [channelName, name].concat(args)); + } + + // If the command isn't handled, log it in DEBUG mode and exit + if (commands && (commands[name] || commands["default"])) { + var handler = commands[name] || commands["default"]; + args = commands[name] ? args : arguments; + Radio._callHandler(handler.callback, handler.context, args); + } else { + Radio.debugLog("An unhandled command was fired", name, channelName); + } + + return this; + }, + + // Register a handler for a command. + comply: function comply(name, callback, context) { + if (Radio._eventsApi(this, "comply", name, [callback, context])) { + return this; + } + this._commands || (this._commands = {}); + + if (this._commands[name]) { + Radio.debugLog("A command was overwritten", name, this.channelName); + } + + this._commands[name] = { + callback: callback, + context: context || this + }; + + return this; + }, + + // Register a handler for a command that happens just once. + complyOnce: function complyOnce(name, callback, context) { + if (Radio._eventsApi(this, "complyOnce", name, [callback, context])) { + return this; + } + var self = this; + + var once = _.once(function () { + self.stopComplying(name); + return callback.apply(this, arguments); + }); + + return this.comply(name, once, context); + }, + + // Remove handler(s) + stopComplying: function stopComplying(name, callback, context) { + if (Radio._eventsApi(this, "stopComplying", name)) { + return this; + } + + // Remove everything if there are no arguments passed + if (!name && !callback && !context) { + delete this._commands; + } else if (!removeHandlers(this._commands, name, callback, context)) { + Radio.debugLog("Attempted to remove the unregistered command", name, this.channelName); + } + + return this; + } + }; + + /* + * Backbone.Radio.Requests + * ----------------------- + * A messaging system for requesting data. + * + */ + + function makeCallback(callback) { + return _.isFunction(callback) ? callback : function () { + return callback; + }; + } + + Radio.Requests = { + + // Make a request + request: function request(name) { + var args = _.rest(arguments); + var results = Radio._eventsApi(this, "request", name, args); + if (results) { + return results; + } + var channelName = this.channelName; + var requests = this._requests; + + // Check if we should log the request, and if so, do it + if (channelName && this._tunedIn) { + Radio.log.apply(this, [channelName, name].concat(args)); + } + + // If the request isn't handled, log it in DEBUG mode and exit + if (requests && (requests[name] || requests["default"])) { + var handler = requests[name] || requests["default"]; + args = requests[name] ? args : arguments; + return Radio._callHandler(handler.callback, handler.context, args); + } else { + Radio.debugLog("An unhandled request was fired", name, channelName); + } + }, + + // Set up a handler for a request + reply: function reply(name, callback, context) { + if (Radio._eventsApi(this, "reply", name, [callback, context])) { + return this; + } + + this._requests || (this._requests = {}); + + if (this._requests[name]) { + Radio.debugLog("A request was overwritten", name, this.channelName); + } + + this._requests[name] = { + callback: makeCallback(callback), + context: context || this + }; + + return this; + }, + + // Set up a handler that can only be requested once + replyOnce: function replyOnce(name, callback, context) { + if (Radio._eventsApi(this, "replyOnce", name, [callback, context])) { + return this; + } + + var self = this; + + var once = _.once(function () { + self.stopReplying(name); + return makeCallback(callback).apply(this, arguments); + }); + + return this.reply(name, once, context); + }, + + // Remove handler(s) + stopReplying: function stopReplying(name, callback, context) { + if (Radio._eventsApi(this, "stopReplying", name)) { + return this; + } + + // Remove everything if there are no arguments passed + if (!name && !callback && !context) { + delete this._requests; + } else if (!removeHandlers(this._requests, name, callback, context)) { + Radio.debugLog("Attempted to remove the unregistered request", name, this.channelName); + } + + return this; + } + }; + + /* + * Backbone.Radio.channel + * ---------------------- + * Get a reference to a channel by name. + * + */ + + Radio._channels = {}; + + Radio.channel = function (channelName) { + if (!channelName) { + throw new Error("You must provide a name for the channel."); + } + + if (Radio._channels[channelName]) { + return Radio._channels[channelName]; + } else { + return Radio._channels[channelName] = new Radio.Channel(channelName); + } + }; + + /* + * Backbone.Radio.Channel + * ---------------------- + * A Channel is an object that extends from Backbone.Events, + * Radio.Commands, and Radio.Requests. + * + */ + + Radio.Channel = function (channelName) { + this.channelName = channelName; + }; + + _.extend(Radio.Channel.prototype, Backbone.Events, Radio.Commands, Radio.Requests, { + + // Remove all handlers from the messaging systems of this channel + reset: function reset() { + this.off(); + this.stopListening(); + this.stopComplying(); + this.stopReplying(); + return this; + } + }); + + /* + * Top-level API + * ------------- + * Supplies the 'top-level API' for working with Channels directly + * from Backbone.Radio. + * + */ + + var channel, + args, + systems = [Backbone.Events, Radio.Commands, Radio.Requests]; + + _.each(systems, function (system) { + _.each(system, function (method, methodName) { + Radio[methodName] = function (channelName) { + args = _.rest(arguments); + channel = this.channel(channelName); + return channel[methodName].apply(channel, args); + }; + }); + }); + + Radio.reset = function (channelName) { + var channels = !channelName ? this._channels : [this._channels[channelName]]; + _.invoke(channels, "reset"); + }; + + var backbone_radio = Radio; + + return backbone_radio; +}); +//# sourceMappingURL=./backbone.radio.js.map +},{"backbone":21,"underscore":36}],17:[function(require,module,exports){ +(function (process,global){ +/*! + * @overview es6-promise - a tiny implementation of Promises/A+. + * @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald) + * @license Licensed under MIT license + * See https://raw.githubusercontent.com/jakearchibald/es6-promise/master/LICENSE + * @version 2.3.0 + */ + +(function() { + "use strict"; + function lib$es6$promise$utils$$objectOrFunction(x) { + return typeof x === 'function' || (typeof x === 'object' && x !== null); + } + + function lib$es6$promise$utils$$isFunction(x) { + return typeof x === 'function'; + } + + function lib$es6$promise$utils$$isMaybeThenable(x) { + return typeof x === 'object' && x !== null; + } + + var lib$es6$promise$utils$$_isArray; + if (!Array.isArray) { + lib$es6$promise$utils$$_isArray = function (x) { + return Object.prototype.toString.call(x) === '[object Array]'; + }; + } else { + lib$es6$promise$utils$$_isArray = Array.isArray; + } + + var lib$es6$promise$utils$$isArray = lib$es6$promise$utils$$_isArray; + var lib$es6$promise$asap$$len = 0; + var lib$es6$promise$asap$$toString = {}.toString; + var lib$es6$promise$asap$$vertxNext; + var lib$es6$promise$asap$$customSchedulerFn; + + var lib$es6$promise$asap$$asap = function asap(callback, arg) { + lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len] = callback; + lib$es6$promise$asap$$queue[lib$es6$promise$asap$$len + 1] = arg; + lib$es6$promise$asap$$len += 2; + if (lib$es6$promise$asap$$len === 2) { + // If len is 2, that means that we need to schedule an async flush. + // If additional callbacks are queued before the queue is flushed, they + // will be processed by this flush that we are scheduling. + if (lib$es6$promise$asap$$customSchedulerFn) { + lib$es6$promise$asap$$customSchedulerFn(lib$es6$promise$asap$$flush); + } else { + lib$es6$promise$asap$$scheduleFlush(); + } + } + } + + function lib$es6$promise$asap$$setScheduler(scheduleFn) { + lib$es6$promise$asap$$customSchedulerFn = scheduleFn; + } + + function lib$es6$promise$asap$$setAsap(asapFn) { + lib$es6$promise$asap$$asap = asapFn; + } + + var lib$es6$promise$asap$$browserWindow = (typeof window !== 'undefined') ? window : undefined; + var lib$es6$promise$asap$$browserGlobal = lib$es6$promise$asap$$browserWindow || {}; + var lib$es6$promise$asap$$BrowserMutationObserver = lib$es6$promise$asap$$browserGlobal.MutationObserver || lib$es6$promise$asap$$browserGlobal.WebKitMutationObserver; + var lib$es6$promise$asap$$isNode = typeof process !== 'undefined' && {}.toString.call(process) === '[object process]'; + + // test for web worker but not in IE10 + var lib$es6$promise$asap$$isWorker = typeof Uint8ClampedArray !== 'undefined' && + typeof importScripts !== 'undefined' && + typeof MessageChannel !== 'undefined'; + + // node + function lib$es6$promise$asap$$useNextTick() { + var nextTick = process.nextTick; + // node version 0.10.x displays a deprecation warning when nextTick is used recursively + // setImmediate should be used instead instead + var version = process.versions.node.match(/^(?:(\d+)\.)?(?:(\d+)\.)?(\*|\d+)$/); + if (Array.isArray(version) && version[1] === '0' && version[2] === '10') { + nextTick = setImmediate; + } + return function() { + nextTick(lib$es6$promise$asap$$flush); + }; + } + + // vertx + function lib$es6$promise$asap$$useVertxTimer() { + return function() { + lib$es6$promise$asap$$vertxNext(lib$es6$promise$asap$$flush); + }; + } + + function lib$es6$promise$asap$$useMutationObserver() { + var iterations = 0; + var observer = new lib$es6$promise$asap$$BrowserMutationObserver(lib$es6$promise$asap$$flush); + var node = document.createTextNode(''); + observer.observe(node, { characterData: true }); + + return function() { + node.data = (iterations = ++iterations % 2); + }; + } + + // web worker + function lib$es6$promise$asap$$useMessageChannel() { + var channel = new MessageChannel(); + channel.port1.onmessage = lib$es6$promise$asap$$flush; + return function () { + channel.port2.postMessage(0); + }; + } + + function lib$es6$promise$asap$$useSetTimeout() { + return function() { + setTimeout(lib$es6$promise$asap$$flush, 1); + }; + } + + var lib$es6$promise$asap$$queue = new Array(1000); + function lib$es6$promise$asap$$flush() { + for (var i = 0; i < lib$es6$promise$asap$$len; i+=2) { + var callback = lib$es6$promise$asap$$queue[i]; + var arg = lib$es6$promise$asap$$queue[i+1]; + + callback(arg); + + lib$es6$promise$asap$$queue[i] = undefined; + lib$es6$promise$asap$$queue[i+1] = undefined; + } + + lib$es6$promise$asap$$len = 0; + } + + function lib$es6$promise$asap$$attemptVertex() { + try { + var r = require; + var vertx = r('vertx'); + lib$es6$promise$asap$$vertxNext = vertx.runOnLoop || vertx.runOnContext; + return lib$es6$promise$asap$$useVertxTimer(); + } catch(e) { + return lib$es6$promise$asap$$useSetTimeout(); + } + } + + var lib$es6$promise$asap$$scheduleFlush; + // Decide what async method to use to triggering processing of queued callbacks: + if (lib$es6$promise$asap$$isNode) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useNextTick(); + } else if (lib$es6$promise$asap$$BrowserMutationObserver) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMutationObserver(); + } else if (lib$es6$promise$asap$$isWorker) { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useMessageChannel(); + } else if (lib$es6$promise$asap$$browserWindow === undefined && typeof require === 'function') { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$attemptVertex(); + } else { + lib$es6$promise$asap$$scheduleFlush = lib$es6$promise$asap$$useSetTimeout(); + } + + function lib$es6$promise$$internal$$noop() {} + + var lib$es6$promise$$internal$$PENDING = void 0; + var lib$es6$promise$$internal$$FULFILLED = 1; + var lib$es6$promise$$internal$$REJECTED = 2; + + var lib$es6$promise$$internal$$GET_THEN_ERROR = new lib$es6$promise$$internal$$ErrorObject(); + + function lib$es6$promise$$internal$$selfFullfillment() { + return new TypeError("You cannot resolve a promise with itself"); + } + + function lib$es6$promise$$internal$$cannotReturnOwn() { + return new TypeError('A promises callback cannot return that same promise.'); + } + + function lib$es6$promise$$internal$$getThen(promise) { + try { + return promise.then; + } catch(error) { + lib$es6$promise$$internal$$GET_THEN_ERROR.error = error; + return lib$es6$promise$$internal$$GET_THEN_ERROR; + } + } + + function lib$es6$promise$$internal$$tryThen(then, value, fulfillmentHandler, rejectionHandler) { + try { + then.call(value, fulfillmentHandler, rejectionHandler); + } catch(e) { + return e; + } + } + + function lib$es6$promise$$internal$$handleForeignThenable(promise, thenable, then) { + lib$es6$promise$asap$$asap(function(promise) { + var sealed = false; + var error = lib$es6$promise$$internal$$tryThen(then, thenable, function(value) { + if (sealed) { return; } + sealed = true; + if (thenable !== value) { + lib$es6$promise$$internal$$resolve(promise, value); + } else { + lib$es6$promise$$internal$$fulfill(promise, value); + } + }, function(reason) { + if (sealed) { return; } + sealed = true; + + lib$es6$promise$$internal$$reject(promise, reason); + }, 'Settle: ' + (promise._label || ' unknown promise')); + + if (!sealed && error) { + sealed = true; + lib$es6$promise$$internal$$reject(promise, error); + } + }, promise); + } + + function lib$es6$promise$$internal$$handleOwnThenable(promise, thenable) { + if (thenable._state === lib$es6$promise$$internal$$FULFILLED) { + lib$es6$promise$$internal$$fulfill(promise, thenable._result); + } else if (thenable._state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, thenable._result); + } else { + lib$es6$promise$$internal$$subscribe(thenable, undefined, function(value) { + lib$es6$promise$$internal$$resolve(promise, value); + }, function(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + }); + } + } + + function lib$es6$promise$$internal$$handleMaybeThenable(promise, maybeThenable) { + if (maybeThenable.constructor === promise.constructor) { + lib$es6$promise$$internal$$handleOwnThenable(promise, maybeThenable); + } else { + var then = lib$es6$promise$$internal$$getThen(maybeThenable); + + if (then === lib$es6$promise$$internal$$GET_THEN_ERROR) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$GET_THEN_ERROR.error); + } else if (then === undefined) { + lib$es6$promise$$internal$$fulfill(promise, maybeThenable); + } else if (lib$es6$promise$utils$$isFunction(then)) { + lib$es6$promise$$internal$$handleForeignThenable(promise, maybeThenable, then); + } else { + lib$es6$promise$$internal$$fulfill(promise, maybeThenable); + } + } + } + + function lib$es6$promise$$internal$$resolve(promise, value) { + if (promise === value) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$selfFullfillment()); + } else if (lib$es6$promise$utils$$objectOrFunction(value)) { + lib$es6$promise$$internal$$handleMaybeThenable(promise, value); + } else { + lib$es6$promise$$internal$$fulfill(promise, value); + } + } + + function lib$es6$promise$$internal$$publishRejection(promise) { + if (promise._onerror) { + promise._onerror(promise._result); + } + + lib$es6$promise$$internal$$publish(promise); + } + + function lib$es6$promise$$internal$$fulfill(promise, value) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } + + promise._result = value; + promise._state = lib$es6$promise$$internal$$FULFILLED; + + if (promise._subscribers.length !== 0) { + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, promise); + } + } + + function lib$es6$promise$$internal$$reject(promise, reason) { + if (promise._state !== lib$es6$promise$$internal$$PENDING) { return; } + promise._state = lib$es6$promise$$internal$$REJECTED; + promise._result = reason; + + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publishRejection, promise); + } + + function lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection) { + var subscribers = parent._subscribers; + var length = subscribers.length; + + parent._onerror = null; + + subscribers[length] = child; + subscribers[length + lib$es6$promise$$internal$$FULFILLED] = onFulfillment; + subscribers[length + lib$es6$promise$$internal$$REJECTED] = onRejection; + + if (length === 0 && parent._state) { + lib$es6$promise$asap$$asap(lib$es6$promise$$internal$$publish, parent); + } + } + + function lib$es6$promise$$internal$$publish(promise) { + var subscribers = promise._subscribers; + var settled = promise._state; + + if (subscribers.length === 0) { return; } + + var child, callback, detail = promise._result; + + for (var i = 0; i < subscribers.length; i += 3) { + child = subscribers[i]; + callback = subscribers[i + settled]; + + if (child) { + lib$es6$promise$$internal$$invokeCallback(settled, child, callback, detail); + } else { + callback(detail); + } + } + + promise._subscribers.length = 0; + } + + function lib$es6$promise$$internal$$ErrorObject() { + this.error = null; + } + + var lib$es6$promise$$internal$$TRY_CATCH_ERROR = new lib$es6$promise$$internal$$ErrorObject(); + + function lib$es6$promise$$internal$$tryCatch(callback, detail) { + try { + return callback(detail); + } catch(e) { + lib$es6$promise$$internal$$TRY_CATCH_ERROR.error = e; + return lib$es6$promise$$internal$$TRY_CATCH_ERROR; + } + } + + function lib$es6$promise$$internal$$invokeCallback(settled, promise, callback, detail) { + var hasCallback = lib$es6$promise$utils$$isFunction(callback), + value, error, succeeded, failed; + + if (hasCallback) { + value = lib$es6$promise$$internal$$tryCatch(callback, detail); + + if (value === lib$es6$promise$$internal$$TRY_CATCH_ERROR) { + failed = true; + error = value.error; + value = null; + } else { + succeeded = true; + } + + if (promise === value) { + lib$es6$promise$$internal$$reject(promise, lib$es6$promise$$internal$$cannotReturnOwn()); + return; + } + + } else { + value = detail; + succeeded = true; + } + + if (promise._state !== lib$es6$promise$$internal$$PENDING) { + // noop + } else if (hasCallback && succeeded) { + lib$es6$promise$$internal$$resolve(promise, value); + } else if (failed) { + lib$es6$promise$$internal$$reject(promise, error); + } else if (settled === lib$es6$promise$$internal$$FULFILLED) { + lib$es6$promise$$internal$$fulfill(promise, value); + } else if (settled === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } + } + + function lib$es6$promise$$internal$$initializePromise(promise, resolver) { + try { + resolver(function resolvePromise(value){ + lib$es6$promise$$internal$$resolve(promise, value); + }, function rejectPromise(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + }); + } catch(e) { + lib$es6$promise$$internal$$reject(promise, e); + } + } + + function lib$es6$promise$enumerator$$Enumerator(Constructor, input) { + var enumerator = this; + + enumerator._instanceConstructor = Constructor; + enumerator.promise = new Constructor(lib$es6$promise$$internal$$noop); + + if (enumerator._validateInput(input)) { + enumerator._input = input; + enumerator.length = input.length; + enumerator._remaining = input.length; + + enumerator._init(); + + if (enumerator.length === 0) { + lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); + } else { + enumerator.length = enumerator.length || 0; + enumerator._enumerate(); + if (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(enumerator.promise, enumerator._result); + } + } + } else { + lib$es6$promise$$internal$$reject(enumerator.promise, enumerator._validationError()); + } + } + + lib$es6$promise$enumerator$$Enumerator.prototype._validateInput = function(input) { + return lib$es6$promise$utils$$isArray(input); + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._validationError = function() { + return new Error('Array Methods must be provided an Array'); + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._init = function() { + this._result = new Array(this.length); + }; + + var lib$es6$promise$enumerator$$default = lib$es6$promise$enumerator$$Enumerator; + + lib$es6$promise$enumerator$$Enumerator.prototype._enumerate = function() { + var enumerator = this; + + var length = enumerator.length; + var promise = enumerator.promise; + var input = enumerator._input; + + for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { + enumerator._eachEntry(input[i], i); + } + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._eachEntry = function(entry, i) { + var enumerator = this; + var c = enumerator._instanceConstructor; + + if (lib$es6$promise$utils$$isMaybeThenable(entry)) { + if (entry.constructor === c && entry._state !== lib$es6$promise$$internal$$PENDING) { + entry._onerror = null; + enumerator._settledAt(entry._state, i, entry._result); + } else { + enumerator._willSettleAt(c.resolve(entry), i); + } + } else { + enumerator._remaining--; + enumerator._result[i] = entry; + } + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._settledAt = function(state, i, value) { + var enumerator = this; + var promise = enumerator.promise; + + if (promise._state === lib$es6$promise$$internal$$PENDING) { + enumerator._remaining--; + + if (state === lib$es6$promise$$internal$$REJECTED) { + lib$es6$promise$$internal$$reject(promise, value); + } else { + enumerator._result[i] = value; + } + } + + if (enumerator._remaining === 0) { + lib$es6$promise$$internal$$fulfill(promise, enumerator._result); + } + }; + + lib$es6$promise$enumerator$$Enumerator.prototype._willSettleAt = function(promise, i) { + var enumerator = this; + + lib$es6$promise$$internal$$subscribe(promise, undefined, function(value) { + enumerator._settledAt(lib$es6$promise$$internal$$FULFILLED, i, value); + }, function(reason) { + enumerator._settledAt(lib$es6$promise$$internal$$REJECTED, i, reason); + }); + }; + function lib$es6$promise$promise$all$$all(entries) { + return new lib$es6$promise$enumerator$$default(this, entries).promise; + } + var lib$es6$promise$promise$all$$default = lib$es6$promise$promise$all$$all; + function lib$es6$promise$promise$race$$race(entries) { + /*jshint validthis:true */ + var Constructor = this; + + var promise = new Constructor(lib$es6$promise$$internal$$noop); + + if (!lib$es6$promise$utils$$isArray(entries)) { + lib$es6$promise$$internal$$reject(promise, new TypeError('You must pass an array to race.')); + return promise; + } + + var length = entries.length; + + function onFulfillment(value) { + lib$es6$promise$$internal$$resolve(promise, value); + } + + function onRejection(reason) { + lib$es6$promise$$internal$$reject(promise, reason); + } + + for (var i = 0; promise._state === lib$es6$promise$$internal$$PENDING && i < length; i++) { + lib$es6$promise$$internal$$subscribe(Constructor.resolve(entries[i]), undefined, onFulfillment, onRejection); + } + + return promise; + } + var lib$es6$promise$promise$race$$default = lib$es6$promise$promise$race$$race; + function lib$es6$promise$promise$resolve$$resolve(object) { + /*jshint validthis:true */ + var Constructor = this; + + if (object && typeof object === 'object' && object.constructor === Constructor) { + return object; + } + + var promise = new Constructor(lib$es6$promise$$internal$$noop); + lib$es6$promise$$internal$$resolve(promise, object); + return promise; + } + var lib$es6$promise$promise$resolve$$default = lib$es6$promise$promise$resolve$$resolve; + function lib$es6$promise$promise$reject$$reject(reason) { + /*jshint validthis:true */ + var Constructor = this; + var promise = new Constructor(lib$es6$promise$$internal$$noop); + lib$es6$promise$$internal$$reject(promise, reason); + return promise; + } + var lib$es6$promise$promise$reject$$default = lib$es6$promise$promise$reject$$reject; + + var lib$es6$promise$promise$$counter = 0; + + function lib$es6$promise$promise$$needsResolver() { + throw new TypeError('You must pass a resolver function as the first argument to the promise constructor'); + } + + function lib$es6$promise$promise$$needsNew() { + throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function."); + } + + var lib$es6$promise$promise$$default = lib$es6$promise$promise$$Promise; + /** + Promise objects represent the eventual result of an asynchronous operation. The + primary way of interacting with a promise is through its `then` method, which + registers callbacks to receive either a promise's eventual value or the reason + why the promise cannot be fulfilled. + + Terminology + ----------- + + - `promise` is an object or function with a `then` method whose behavior conforms to this specification. + - `thenable` is an object or function that defines a `then` method. + - `value` is any legal JavaScript value (including undefined, a thenable, or a promise). + - `exception` is a value that is thrown using the throw statement. + - `reason` is a value that indicates why a promise was rejected. + - `settled` the final resting state of a promise, fulfilled or rejected. + + A promise can be in one of three states: pending, fulfilled, or rejected. + + Promises that are fulfilled have a fulfillment value and are in the fulfilled + state. Promises that are rejected have a rejection reason and are in the + rejected state. A fulfillment value is never a thenable. + + Promises can also be said to *resolve* a value. If this value is also a + promise, then the original promise's settled state will match the value's + settled state. So a promise that *resolves* a promise that rejects will + itself reject, and a promise that *resolves* a promise that fulfills will + itself fulfill. + + + Basic Usage: + ------------ + + ```js + var promise = new Promise(function(resolve, reject) { + // on success + resolve(value); + + // on failure + reject(reason); + }); + + promise.then(function(value) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Advanced Usage: + --------------- + + Promises shine when abstracting away asynchronous interactions such as + `XMLHttpRequest`s. + + ```js + function getJSON(url) { + return new Promise(function(resolve, reject){ + var xhr = new XMLHttpRequest(); + + xhr.open('GET', url); + xhr.onreadystatechange = handler; + xhr.responseType = 'json'; + xhr.setRequestHeader('Accept', 'application/json'); + xhr.send(); + + function handler() { + if (this.readyState === this.DONE) { + if (this.status === 200) { + resolve(this.response); + } else { + reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']')); + } + } + }; + }); + } + + getJSON('/posts.json').then(function(json) { + // on fulfillment + }, function(reason) { + // on rejection + }); + ``` + + Unlike callbacks, promises are great composable primitives. + + ```js + Promise.all([ + getJSON('/posts'), + getJSON('/comments') + ]).then(function(values){ + values[0] // => postsJSON + values[1] // => commentsJSON + + return values; + }); + ``` + + @class Promise + @param {function} resolver + Useful for tooling. + @constructor + */ + function lib$es6$promise$promise$$Promise(resolver) { + this._id = lib$es6$promise$promise$$counter++; + this._state = undefined; + this._result = undefined; + this._subscribers = []; + + if (lib$es6$promise$$internal$$noop !== resolver) { + if (!lib$es6$promise$utils$$isFunction(resolver)) { + lib$es6$promise$promise$$needsResolver(); + } + + if (!(this instanceof lib$es6$promise$promise$$Promise)) { + lib$es6$promise$promise$$needsNew(); + } + + lib$es6$promise$$internal$$initializePromise(this, resolver); + } + } + + lib$es6$promise$promise$$Promise.all = lib$es6$promise$promise$all$$default; + lib$es6$promise$promise$$Promise.race = lib$es6$promise$promise$race$$default; + lib$es6$promise$promise$$Promise.resolve = lib$es6$promise$promise$resolve$$default; + lib$es6$promise$promise$$Promise.reject = lib$es6$promise$promise$reject$$default; + lib$es6$promise$promise$$Promise._setScheduler = lib$es6$promise$asap$$setScheduler; + lib$es6$promise$promise$$Promise._setAsap = lib$es6$promise$asap$$setAsap; + lib$es6$promise$promise$$Promise._asap = lib$es6$promise$asap$$asap; + + lib$es6$promise$promise$$Promise.prototype = { + constructor: lib$es6$promise$promise$$Promise, + + /** + The primary way of interacting with a promise is through its `then` method, + which registers callbacks to receive either a promise's eventual value or the + reason why the promise cannot be fulfilled. + + ```js + findUser().then(function(user){ + // user is available + }, function(reason){ + // user is unavailable, and you are given the reason why + }); + ``` + + Chaining + -------- + + The return value of `then` is itself a promise. This second, 'downstream' + promise is resolved with the return value of the first promise's fulfillment + or rejection handler, or rejected if the handler throws an exception. + + ```js + findUser().then(function (user) { + return user.name; + }, function (reason) { + return 'default name'; + }).then(function (userName) { + // If `findUser` fulfilled, `userName` will be the user's name, otherwise it + // will be `'default name'` + }); + + findUser().then(function (user) { + throw new Error('Found user, but still unhappy'); + }, function (reason) { + throw new Error('`findUser` rejected and we're unhappy'); + }).then(function (value) { + // never reached + }, function (reason) { + // if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'. + // If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'. + }); + ``` + If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream. + + ```js + findUser().then(function (user) { + throw new PedagogicalException('Upstream error'); + }).then(function (value) { + // never reached + }).then(function (value) { + // never reached + }, function (reason) { + // The `PedgagocialException` is propagated all the way down to here + }); + ``` + + Assimilation + ------------ + + Sometimes the value you want to propagate to a downstream promise can only be + retrieved asynchronously. This can be achieved by returning a promise in the + fulfillment or rejection handler. The downstream promise will then be pending + until the returned promise is settled. This is called *assimilation*. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // The user's comments are now available + }); + ``` + + If the assimliated promise rejects, then the downstream promise will also reject. + + ```js + findUser().then(function (user) { + return findCommentsByAuthor(user); + }).then(function (comments) { + // If `findCommentsByAuthor` fulfills, we'll have the value here + }, function (reason) { + // If `findCommentsByAuthor` rejects, we'll have the reason here + }); + ``` + + Simple Example + -------------- + + Synchronous Example + + ```javascript + var result; + + try { + result = findResult(); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + findResult(function(result, err){ + if (err) { + // failure + } else { + // success + } + }); + ``` + + Promise Example; + + ```javascript + findResult().then(function(result){ + // success + }, function(reason){ + // failure + }); + ``` + + Advanced Example + -------------- + + Synchronous Example + + ```javascript + var author, books; + + try { + author = findAuthor(); + books = findBooksByAuthor(author); + // success + } catch(reason) { + // failure + } + ``` + + Errback Example + + ```js + + function foundBooks(books) { + + } + + function failure(reason) { + + } + + findAuthor(function(author, err){ + if (err) { + failure(err); + // failure + } else { + try { + findBoooksByAuthor(author, function(books, err) { + if (err) { + failure(err); + } else { + try { + foundBooks(books); + } catch(reason) { + failure(reason); + } + } + }); + } catch(error) { + failure(err); + } + // success + } + }); + ``` + + Promise Example; + + ```javascript + findAuthor(). + then(findBooksByAuthor). + then(function(books){ + // found books + }).catch(function(reason){ + // something went wrong + }); + ``` + + @method then + @param {Function} onFulfilled + @param {Function} onRejected + Useful for tooling. + @return {Promise} + */ + then: function(onFulfillment, onRejection) { + var parent = this; + var state = parent._state; + + if (state === lib$es6$promise$$internal$$FULFILLED && !onFulfillment || state === lib$es6$promise$$internal$$REJECTED && !onRejection) { + return this; + } + + var child = new this.constructor(lib$es6$promise$$internal$$noop); + var result = parent._result; + + if (state) { + var callback = arguments[state - 1]; + lib$es6$promise$asap$$asap(function(){ + lib$es6$promise$$internal$$invokeCallback(state, child, callback, result); + }); + } else { + lib$es6$promise$$internal$$subscribe(parent, child, onFulfillment, onRejection); + } + + return child; + }, + + /** + `catch` is simply sugar for `then(undefined, onRejection)` which makes it the same + as the catch block of a try/catch statement. + + ```js + function findAuthor(){ + throw new Error('couldn't find that author'); + } + + // synchronous + try { + findAuthor(); + } catch(reason) { + // something went wrong + } + + // async with promises + findAuthor().catch(function(reason){ + // something went wrong + }); + ``` + + @method catch + @param {Function} onRejection + Useful for tooling. + @return {Promise} + */ + 'catch': function(onRejection) { + return this.then(null, onRejection); + } + }; + function lib$es6$promise$polyfill$$polyfill() { + var local; + + if (typeof global !== 'undefined') { + local = global; + } else if (typeof self !== 'undefined') { + local = self; + } else { + try { + local = Function('return this')(); + } catch (e) { + throw new Error('polyfill failed because global object is unavailable in this environment'); + } + } + + var P = local.Promise; + + if (P && Object.prototype.toString.call(P.resolve()) === '[object Promise]' && !P.cast) { + return; + } + + local.Promise = lib$es6$promise$promise$$default; + } + var lib$es6$promise$polyfill$$default = lib$es6$promise$polyfill$$polyfill; + + var lib$es6$promise$umd$$ES6Promise = { + 'Promise': lib$es6$promise$promise$$default, + 'polyfill': lib$es6$promise$polyfill$$default + }; + + /* global define:true module:true window: true */ + if (typeof define === 'function' && define['amd']) { + define(function() { return lib$es6$promise$umd$$ES6Promise; }); + } else if (typeof module !== 'undefined' && module['exports']) { + module['exports'] = lib$es6$promise$umd$$ES6Promise; + } else if (typeof this !== 'undefined') { + this['ES6Promise'] = lib$es6$promise$umd$$ES6Promise; + } + + lib$es6$promise$polyfill$$default(); +}).call(this); + + +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"_process":23}],18:[function(require,module,exports){ // Backbone.Stickit v0.8.0, MIT Licensed // Copyright (c) 2012 The New York Times, CMS Group, Matthew DeLambo @@ -8088,7 +10342,150 @@ arguments[4][7][0].apply(exports,arguments) })); -},{"backbone":11,"underscore":25}],11:[function(require,module,exports){ +},{"backbone":21,"underscore":36}],19:[function(require,module,exports){ +(function (global, factory) { + typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory(require("backbone"), require("backbone-metal")) : typeof define === "function" && define.amd ? define(["backbone", "backbone-metal"], factory) : global.Backbone.Storage = factory(global.Backbone, global.Metal); +})(this, function (Backbone, Metal) { + "use strict"; + + var Storage = Backbone.Storage = Metal.Class.extend({ + + /** + * The model class to store. + * @type {Backbone.Model} + */ + model: Backbone.Model, + + /** + * The collection class to store. + * @type {Backbone.Collection} + */ + collection: Backbone.Collection, + + /** + * @public + * @constructs Storage + */ + constructor: function constructor() { + var _this = this; + this.records = new this.collection(); + this.listenToOnce(this.records, "sync", function () { + _this._hasSynced = true; + }); + this._super.apply(this, arguments); + }, + + /** + * Find a specific model from the store or fetch it from the server and insert + * it into the store. + * + * @public + * @instance + * @method find + * @memberOf Storage + * @param {Number|String|Object|Backbone.Model} model - The model to find. + * @returns {Promise} - A promise that will resolve to the model. + */ + find: function find(model) { + var _this = this; + var record = this.records.get(model); + if (record) { + return Promise.resolve(record); + } else { + model = this._ensureModel(model); + return Promise.resolve(model.fetch()).then(function () { + return _this.insert(model); + }); + } + }, + + /** + * Find all the models in the store or fetch them from the server if they + * haven't been fetched before. + * + * @public + * @instance + * @method findAll + * @memberOf Storage + * @returns {Promise} - A promise that will resolve to the entire collection. + */ + findAll: function findAll() { + var _this = this; + if (this._hasSynced) { + return Promise.resolve(this.records); + } else { + return Promise.resolve(this.records.fetch()).then(function () { + return _this.records; + }); + } + }, + + /** + * Save a model to the server. + * + * @public + * @instance + * @method save + * @memberOf Storage + * @param {Number|String|Object|Backbone.Model} model - The model to save + * @returns {Promise} - A promise that will resolve to the saved model. + */ + save: function save(model) { + var _this = this; + var record = this.records.get(model); + model = record || this._ensureModel(model); + return Promise.resolve(model.save()).then(function () { + if (!record) { + _this.insert(model); + } + return model; + }); + }, + + /** + * Insert a model into the store. + * + * @public + * @instance + * @method insert + * @memberOf Storage + * @params {Object|Backbone.Model} - The model to add. + * @returns {Promise} - A promise that will resolve to the added model. + */ + insert: function insert(model) { + model = this.records.add(model); + return Promise.resolve(model); + }, + + /** + * Ensure that we have a real model from an id, object, or model. + * + * @private + * @instance + * @method _ensureModel + * @memberOf Storage + * @params {Number|String|Object|Backbone.Model} - An id, object, or model. + * @returns {Backbone.Model} - The model. + */ + _ensureModel: function _ensureModel(model) { + if (model instanceof this.model) { + return model; + } else if (typeof model === "object") { + return new this.model(model); + } else { + return new this.model({ id: model }); + } + } + }); + + var backbone_storage = Storage; + + return backbone_storage; +}); +//# sourceMappingURL=./backbone.storage.js.map +},{"backbone":21,"backbone-metal":20}],20:[function(require,module,exports){ +arguments[4][3][0].apply(exports,arguments) +},{"backbone":21,"dup":3,"underscore":36}],21:[function(require,module,exports){ (function (global){ // Backbone.js 1.2.1 @@ -9965,9 +12362,69 @@ arguments[4][7][0].apply(exports,arguments) })); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"jquery":22,"underscore":12}],12:[function(require,module,exports){ -arguments[4][7][0].apply(exports,arguments) -},{"dup":7}],13:[function(require,module,exports){ +},{"jquery":33,"underscore":22}],22:[function(require,module,exports){ +arguments[4][9][0].apply(exports,arguments) +},{"dup":9}],23:[function(require,module,exports){ +// shim for using process in browser + +var process = module.exports = {}; +var queue = []; +var draining = false; + +function drainQueue() { + if (draining) { + return; + } + draining = true; + var currentQueue; + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + var i = -1; + while (++i < len) { + currentQueue[i](); + } + len = queue.length; + } + draining = false; +} +process.nextTick = function (fun) { + queue.push(fun); + if (!draining) { + setTimeout(drainQueue, 0); + } +}; + +process.title = 'browser'; +process.browser = true; +process.env = {}; +process.argv = []; +process.version = ''; // empty string to avoid regexp issues +process.versions = {}; + +function noop() {} + +process.on = noop; +process.addListener = noop; +process.once = noop; +process.off = noop; +process.removeListener = noop; +process.removeAllListeners = noop; +process.emit = noop; + +process.binding = function (name) { + throw new Error('process.binding is not supported'); +}; + +// TODO(shtylman) +process.cwd = function () { return '/' }; +process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); +}; +process.umask = function() { return 0; }; + +},{}],24:[function(require,module,exports){ /*! Hammer.JS - v2.0.4 - 2014-09-28 * http://hammerjs.github.io/ * @@ -12432,7 +14889,7 @@ if (typeof define == TYPE_FUNCTION && define.amd) { })(window, document, 'Hammer'); -},{}],14:[function(require,module,exports){ +},{}],25:[function(require,module,exports){ "use strict"; /*globals Handlebars: true */ var base = require("./handlebars/base"); @@ -12465,7 +14922,7 @@ var Handlebars = create(); Handlebars.create = create; exports["default"] = Handlebars; -},{"./handlebars/base":15,"./handlebars/exception":16,"./handlebars/runtime":17,"./handlebars/safe-string":18,"./handlebars/utils":19}],15:[function(require,module,exports){ +},{"./handlebars/base":26,"./handlebars/exception":27,"./handlebars/runtime":28,"./handlebars/safe-string":29,"./handlebars/utils":30}],26:[function(require,module,exports){ "use strict"; var Utils = require("./utils"); var Exception = require("./exception")["default"]; @@ -12646,7 +15103,7 @@ exports.log = log;var createFrame = function(object) { return obj; }; exports.createFrame = createFrame; -},{"./exception":16,"./utils":19}],16:[function(require,module,exports){ +},{"./exception":27,"./utils":30}],27:[function(require,module,exports){ "use strict"; var errorProps = ['description', 'fileName', 'lineNumber', 'message', 'name', 'number', 'stack']; @@ -12675,7 +15132,7 @@ function Exception(message, node) { Exception.prototype = new Error(); exports["default"] = Exception; -},{}],17:[function(require,module,exports){ +},{}],28:[function(require,module,exports){ "use strict"; var Utils = require("./utils"); var Exception = require("./exception")["default"]; @@ -12813,7 +15270,7 @@ exports.program = program;function invokePartial(partial, name, context, helpers exports.invokePartial = invokePartial;function noop() { return ""; } exports.noop = noop; -},{"./base":15,"./exception":16,"./utils":19}],18:[function(require,module,exports){ +},{"./base":26,"./exception":27,"./utils":30}],29:[function(require,module,exports){ "use strict"; // Build out our basic SafeString type function SafeString(string) { @@ -12825,7 +15282,7 @@ SafeString.prototype.toString = function() { }; exports["default"] = SafeString; -},{}],19:[function(require,module,exports){ +},{}],30:[function(require,module,exports){ "use strict"; /*jshint -W004 */ var SafeString = require("./safe-string")["default"]; @@ -12902,12 +15359,12 @@ exports.escapeExpression = escapeExpression;function isEmpty(value) { } exports.isEmpty = isEmpty; -},{"./safe-string":18}],20:[function(require,module,exports){ +},{"./safe-string":29}],31:[function(require,module,exports){ // Create a simple path alias to allow browserify to resolve // the runtime on a supported path. module.exports = require('./dist/cjs/handlebars.runtime'); -},{"./dist/cjs/handlebars.runtime":14}],21:[function(require,module,exports){ +},{"./dist/cjs/handlebars.runtime":25}],32:[function(require,module,exports){ // i18next, v1.10.2 // Copyright (c)2015 Jan Mühlemann (jamuhl). // Distributed under MIT license @@ -15189,7 +17646,7 @@ module.exports = require('./dist/cjs/handlebars.runtime'); i18n.noConflict = noConflict; })(typeof exports === 'undefined' ? window : exports); -},{}],22:[function(require,module,exports){ +},{}],33:[function(require,module,exports){ /*! * jQuery JavaScript Library v2.1.1 * http://jquery.com/ @@ -24381,7 +26838,7 @@ return jQuery; })); -},{}],23:[function(require,module,exports){ +},{}],34:[function(require,module,exports){ (function (global){ /** * @license @@ -36736,7 +39193,7 @@ return jQuery; }.call(this)); }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],24:[function(require,module,exports){ +},{}],35:[function(require,module,exports){ /*! * numeral.js * version : 1.5.3 @@ -37417,9 +39874,9 @@ return jQuery; } }).call(this); -},{}],25:[function(require,module,exports){ -arguments[4][7][0].apply(exports,arguments) -},{"dup":7}],26:[function(require,module,exports){ +},{}],36:[function(require,module,exports){ +arguments[4][9][0].apply(exports,arguments) +},{"dup":9}],37:[function(require,module,exports){ 'use strict'; Object.defineProperty(exports, '__esModule', { @@ -37502,7 +39959,7 @@ var CurrencyHelper = (function () { exports['default'] = new CurrencyHelper(); module.exports = exports['default']; -},{"backbone.radio":8,"numeral":24}],27:[function(require,module,exports){ +},{"backbone.radio":10,"numeral":35}],38:[function(require,module,exports){ (function (global){ // // ## helpers/handlebars @@ -37604,7 +40061,7 @@ exports['default'] = function (handlebars) { module.exports = exports['default']; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./currency":26,"./translate":30,"handlebars/runtime":20}],28:[function(require,module,exports){ +},{"./currency":37,"./translate":41,"handlebars/runtime":31}],39:[function(require,module,exports){ // // #orchestra/storage/local.js // @@ -37686,13 +40143,17 @@ var LocalStorage = (function () { exports['default'] = new LocalStorage(); module.exports = exports['default']; -},{}],29:[function(require,module,exports){ +},{}],40:[function(require,module,exports){ // // helpers.modules // 'use strict'; +Object.defineProperty(exports, '__esModule', { + value: true +}); + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { @@ -37738,9 +40199,10 @@ var ModuleHelpers = (function () { return ModuleHelpers; })(); -module.exports = new ModuleHelpers(); +exports['default'] = new ModuleHelpers(); +module.exports = exports['default']; -},{"lodash":23}],30:[function(require,module,exports){ +},{"lodash":34}],41:[function(require,module,exports){ // // helpers.translate // @@ -37832,7 +40294,7 @@ var TranslateHelpers = (function () { exports['default'] = new TranslateHelpers(); module.exports = exports['default']; -},{"backbone.radio":8,"i18next-client":21}],31:[function(require,module,exports){ +},{"backbone.radio":10,"i18next-client":32}],42:[function(require,module,exports){ // // expose device capibilities to app object. // @@ -37930,7 +40392,7 @@ var Visibility = (function () { exports['default'] = new Visibility(); module.exports = exports['default']; -},{"backbone.radio":8,"jquery":22}],32:[function(require,module,exports){ +},{"backbone.radio":10,"jquery":33}],43:[function(require,module,exports){ // // #orchestra/mixins/touch.view.js // @@ -38050,7 +40512,7 @@ exports['default'] = { }; module.exports = exports['default']; -},{"backbone":11,"hammerjs":13,"jquery":22,"lodash":23}],33:[function(require,module,exports){ +},{"backbone":21,"hammerjs":24,"jquery":33,"lodash":34}],44:[function(require,module,exports){ // // #orchestra/mvc/collection.js // @@ -38095,6 +40557,6 @@ exports['default'] = _backbone2['default'].Collection.extend({ }); module.exports = exports['default']; -},{"backbone":11,"lodash":23}]},{},[1])(1) +},{"backbone":21,"lodash":34}]},{},[1])(1) }); //# sourceMappingURL=orchestra.js.map \ No newline at end of file diff --git a/dist/orchestra.js.map b/dist/orchestra.js.map index d0b0d93..3fd7fd7 100644 --- a/dist/orchestra.js.map +++ b/dist/orchestra.js.map @@ -1 +1 @@ -{"version":3,"names":[],"mappings":"","sources":["orchestra.js"],"sourcesContent":["(function(f){if(typeof exports===\"object\"&&typeof module!==\"undefined\"){module.exports=f()}else if(typeof define===\"function\"&&define.amd){define([],f)}else{var g;if(typeof window!==\"undefined\"){g=window}else if(typeof global!==\"undefined\"){g=global}else if(typeof self!==\"undefined\"){g=self}else{g=this}g.orchestra = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o 2;\n if (obj == null) obj = [];\n if (nativeReduce && obj.reduce === nativeReduce) {\n if (context) iterator = _.bind(iterator, context);\n return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator);\n }\n each(obj, function(value, index, list) {\n if (!initial) {\n memo = value;\n initial = true;\n } else {\n memo = iterator.call(context, memo, value, index, list);\n }\n });\n if (!initial) throw new TypeError(reduceError);\n return memo;\n };\n\n // The right-associative version of reduce, also known as `foldr`.\n // Delegates to **ECMAScript 5**'s native `reduceRight` if available.\n _.reduceRight = _.foldr = function(obj, iterator, memo, context) {\n var initial = arguments.length > 2;\n if (obj == null) obj = [];\n if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {\n if (context) iterator = _.bind(iterator, context);\n return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator);\n }\n var length = obj.length;\n if (length !== +length) {\n var keys = _.keys(obj);\n length = keys.length;\n }\n each(obj, function(value, index, list) {\n index = keys ? keys[--length] : --length;\n if (!initial) {\n memo = obj[index];\n initial = true;\n } else {\n memo = iterator.call(context, memo, obj[index], index, list);\n }\n });\n if (!initial) throw new TypeError(reduceError);\n return memo;\n };\n\n // Return the first value which passes a truth test. Aliased as `detect`.\n _.find = _.detect = function(obj, iterator, context) {\n var result;\n any(obj, function(value, index, list) {\n if (iterator.call(context, value, index, list)) {\n result = value;\n return true;\n }\n });\n return result;\n };\n\n // Return all the elements that pass a truth test.\n // Delegates to **ECMAScript 5**'s native `filter` if available.\n // Aliased as `select`.\n _.filter = _.select = function(obj, iterator, context) {\n var results = [];\n if (obj == null) return results;\n if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);\n each(obj, function(value, index, list) {\n if (iterator.call(context, value, index, list)) results.push(value);\n });\n return results;\n };\n\n // Return all the elements for which a truth test fails.\n _.reject = function(obj, iterator, context) {\n return _.filter(obj, function(value, index, list) {\n return !iterator.call(context, value, index, list);\n }, context);\n };\n\n // Determine whether all of the elements match a truth test.\n // Delegates to **ECMAScript 5**'s native `every` if available.\n // Aliased as `all`.\n _.every = _.all = function(obj, iterator, context) {\n iterator || (iterator = _.identity);\n var result = true;\n if (obj == null) return result;\n if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);\n each(obj, function(value, index, list) {\n if (!(result = result && iterator.call(context, value, index, list))) return breaker;\n });\n return !!result;\n };\n\n // Determine if at least one element in the object matches a truth test.\n // Delegates to **ECMAScript 5**'s native `some` if available.\n // Aliased as `any`.\n var any = _.some = _.any = function(obj, iterator, context) {\n iterator || (iterator = _.identity);\n var result = false;\n if (obj == null) return result;\n if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);\n each(obj, function(value, index, list) {\n if (result || (result = iterator.call(context, value, index, list))) return breaker;\n });\n return !!result;\n };\n\n // Determine if the array or object contains a given value (using `===`).\n // Aliased as `include`.\n _.contains = _.include = function(obj, target) {\n if (obj == null) return false;\n if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;\n return any(obj, function(value) {\n return value === target;\n });\n };\n\n // Invoke a method (with arguments) on every item in a collection.\n _.invoke = function(obj, method) {\n var args = slice.call(arguments, 2);\n var isFunc = _.isFunction(method);\n return _.map(obj, function(value) {\n return (isFunc ? method : value[method]).apply(value, args);\n });\n };\n\n // Convenience version of a common use case of `map`: fetching a property.\n _.pluck = function(obj, key) {\n return _.map(obj, function(value){ return value[key]; });\n };\n\n // Convenience version of a common use case of `filter`: selecting only objects\n // containing specific `key:value` pairs.\n _.where = function(obj, attrs, first) {\n if (_.isEmpty(attrs)) return first ? void 0 : [];\n return _[first ? 'find' : 'filter'](obj, function(value) {\n for (var key in attrs) {\n if (attrs[key] !== value[key]) return false;\n }\n return true;\n });\n };\n\n // Convenience version of a common use case of `find`: getting the first object\n // containing specific `key:value` pairs.\n _.findWhere = function(obj, attrs) {\n return _.where(obj, attrs, true);\n };\n\n // Return the maximum element or (element-based computation).\n // Can't optimize arrays of integers longer than 65,535 elements.\n // See [WebKit Bug 80797](https://bugs.webkit.org/show_bug.cgi?id=80797)\n _.max = function(obj, iterator, context) {\n if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n return Math.max.apply(Math, obj);\n }\n if (!iterator && _.isEmpty(obj)) return -Infinity;\n var result = {computed : -Infinity, value: -Infinity};\n each(obj, function(value, index, list) {\n var computed = iterator ? iterator.call(context, value, index, list) : value;\n computed > result.computed && (result = {value : value, computed : computed});\n });\n return result.value;\n };\n\n // Return the minimum element (or element-based computation).\n _.min = function(obj, iterator, context) {\n if (!iterator && _.isArray(obj) && obj[0] === +obj[0] && obj.length < 65535) {\n return Math.min.apply(Math, obj);\n }\n if (!iterator && _.isEmpty(obj)) return Infinity;\n var result = {computed : Infinity, value: Infinity};\n each(obj, function(value, index, list) {\n var computed = iterator ? iterator.call(context, value, index, list) : value;\n computed < result.computed && (result = {value : value, computed : computed});\n });\n return result.value;\n };\n\n // Shuffle an array, using the modern version of the \n // [Fisher-Yates shuffle](http://en.wikipedia.org/wiki/Fisher–Yates_shuffle).\n _.shuffle = function(obj) {\n var rand;\n var index = 0;\n var shuffled = [];\n each(obj, function(value) {\n rand = _.random(index++);\n shuffled[index - 1] = shuffled[rand];\n shuffled[rand] = value;\n });\n return shuffled;\n };\n\n // Sample **n** random values from an array.\n // If **n** is not specified, returns a single random element from the array.\n // The internal `guard` argument allows it to work with `map`.\n _.sample = function(obj, n, guard) {\n if (arguments.length < 2 || guard) {\n return obj[_.random(obj.length - 1)];\n }\n return _.shuffle(obj).slice(0, Math.max(0, n));\n };\n\n // An internal function to generate lookup iterators.\n var lookupIterator = function(value) {\n return _.isFunction(value) ? value : function(obj){ return obj[value]; };\n };\n\n // Sort the object's values by a criterion produced by an iterator.\n _.sortBy = function(obj, value, context) {\n var iterator = lookupIterator(value);\n return _.pluck(_.map(obj, function(value, index, list) {\n return {\n value: value,\n index: index,\n criteria: iterator.call(context, value, index, list)\n };\n }).sort(function(left, right) {\n var a = left.criteria;\n var b = right.criteria;\n if (a !== b) {\n if (a > b || a === void 0) return 1;\n if (a < b || b === void 0) return -1;\n }\n return left.index - right.index;\n }), 'value');\n };\n\n // An internal function used for aggregate \"group by\" operations.\n var group = function(behavior) {\n return function(obj, value, context) {\n var result = {};\n var iterator = value == null ? _.identity : lookupIterator(value);\n each(obj, function(value, index) {\n var key = iterator.call(context, value, index, obj);\n behavior(result, key, value);\n });\n return result;\n };\n };\n\n // Groups the object's values by a criterion. Pass either a string attribute\n // to group by, or a function that returns the criterion.\n _.groupBy = group(function(result, key, value) {\n (_.has(result, key) ? result[key] : (result[key] = [])).push(value);\n });\n\n // Indexes the object's values by a criterion, similar to `groupBy`, but for\n // when you know that your index values will be unique.\n _.indexBy = group(function(result, key, value) {\n result[key] = value;\n });\n\n // Counts instances of an object that group by a certain criterion. Pass\n // either a string attribute to count by, or a function that returns the\n // criterion.\n _.countBy = group(function(result, key) {\n _.has(result, key) ? result[key]++ : result[key] = 1;\n });\n\n // Use a comparator function to figure out the smallest index at which\n // an object should be inserted so as to maintain order. Uses binary search.\n _.sortedIndex = function(array, obj, iterator, context) {\n iterator = iterator == null ? _.identity : lookupIterator(iterator);\n var value = iterator.call(context, obj);\n var low = 0, high = array.length;\n while (low < high) {\n var mid = (low + high) >>> 1;\n iterator.call(context, array[mid]) < value ? low = mid + 1 : high = mid;\n }\n return low;\n };\n\n // Safely create a real, live array from anything iterable.\n _.toArray = function(obj) {\n if (!obj) return [];\n if (_.isArray(obj)) return slice.call(obj);\n if (obj.length === +obj.length) return _.map(obj, _.identity);\n return _.values(obj);\n };\n\n // Return the number of elements in an object.\n _.size = function(obj) {\n if (obj == null) return 0;\n return (obj.length === +obj.length) ? obj.length : _.keys(obj).length;\n };\n\n // Array Functions\n // ---------------\n\n // Get the first element of an array. Passing **n** will return the first N\n // values in the array. Aliased as `head` and `take`. The **guard** check\n // allows it to work with `_.map`.\n _.first = _.head = _.take = function(array, n, guard) {\n if (array == null) return void 0;\n return (n == null) || guard ? array[0] : slice.call(array, 0, n);\n };\n\n // Returns everything but the last entry of the array. Especially useful on\n // the arguments object. Passing **n** will return all the values in\n // the array, excluding the last N. The **guard** check allows it to work with\n // `_.map`.\n _.initial = function(array, n, guard) {\n return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n));\n };\n\n // Get the last element of an array. Passing **n** will return the last N\n // values in the array. The **guard** check allows it to work with `_.map`.\n _.last = function(array, n, guard) {\n if (array == null) return void 0;\n if ((n == null) || guard) {\n return array[array.length - 1];\n } else {\n return slice.call(array, Math.max(array.length - n, 0));\n }\n };\n\n // Returns everything but the first entry of the array. Aliased as `tail` and `drop`.\n // Especially useful on the arguments object. Passing an **n** will return\n // the rest N values in the array. The **guard**\n // check allows it to work with `_.map`.\n _.rest = _.tail = _.drop = function(array, n, guard) {\n return slice.call(array, (n == null) || guard ? 1 : n);\n };\n\n // Trim out all falsy values from an array.\n _.compact = function(array) {\n return _.filter(array, _.identity);\n };\n\n // Internal implementation of a recursive `flatten` function.\n var flatten = function(input, shallow, output) {\n if (shallow && _.every(input, _.isArray)) {\n return concat.apply(output, input);\n }\n each(input, function(value) {\n if (_.isArray(value) || _.isArguments(value)) {\n shallow ? push.apply(output, value) : flatten(value, shallow, output);\n } else {\n output.push(value);\n }\n });\n return output;\n };\n\n // Flatten out an array, either recursively (by default), or just one level.\n _.flatten = function(array, shallow) {\n return flatten(array, shallow, []);\n };\n\n // Return a version of the array that does not contain the specified value(s).\n _.without = function(array) {\n return _.difference(array, slice.call(arguments, 1));\n };\n\n // Produce a duplicate-free version of the array. If the array has already\n // been sorted, you have the option of using a faster algorithm.\n // Aliased as `unique`.\n _.uniq = _.unique = function(array, isSorted, iterator, context) {\n if (_.isFunction(isSorted)) {\n context = iterator;\n iterator = isSorted;\n isSorted = false;\n }\n var initial = iterator ? _.map(array, iterator, context) : array;\n var results = [];\n var seen = [];\n each(initial, function(value, index) {\n if (isSorted ? (!index || seen[seen.length - 1] !== value) : !_.contains(seen, value)) {\n seen.push(value);\n results.push(array[index]);\n }\n });\n return results;\n };\n\n // Produce an array that contains the union: each distinct element from all of\n // the passed-in arrays.\n _.union = function() {\n return _.uniq(_.flatten(arguments, true));\n };\n\n // Produce an array that contains every item shared between all the\n // passed-in arrays.\n _.intersection = function(array) {\n var rest = slice.call(arguments, 1);\n return _.filter(_.uniq(array), function(item) {\n return _.every(rest, function(other) {\n return _.indexOf(other, item) >= 0;\n });\n });\n };\n\n // Take the difference between one array and a number of other arrays.\n // Only the elements present in just the first array will remain.\n _.difference = function(array) {\n var rest = concat.apply(ArrayProto, slice.call(arguments, 1));\n return _.filter(array, function(value){ return !_.contains(rest, value); });\n };\n\n // Zip together multiple lists into a single array -- elements that share\n // an index go together.\n _.zip = function() {\n var length = _.max(_.pluck(arguments, \"length\").concat(0));\n var results = new Array(length);\n for (var i = 0; i < length; i++) {\n results[i] = _.pluck(arguments, '' + i);\n }\n return results;\n };\n\n // Converts lists into objects. Pass either a single array of `[key, value]`\n // pairs, or two parallel arrays of the same length -- one of keys, and one of\n // the corresponding values.\n _.object = function(list, values) {\n if (list == null) return {};\n var result = {};\n for (var i = 0, length = list.length; i < length; i++) {\n if (values) {\n result[list[i]] = values[i];\n } else {\n result[list[i][0]] = list[i][1];\n }\n }\n return result;\n };\n\n // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**),\n // we need this function. Return the position of the first occurrence of an\n // item in an array, or -1 if the item is not included in the array.\n // Delegates to **ECMAScript 5**'s native `indexOf` if available.\n // If the array is large and already in sort order, pass `true`\n // for **isSorted** to use binary search.\n _.indexOf = function(array, item, isSorted) {\n if (array == null) return -1;\n var i = 0, length = array.length;\n if (isSorted) {\n if (typeof isSorted == 'number') {\n i = (isSorted < 0 ? Math.max(0, length + isSorted) : isSorted);\n } else {\n i = _.sortedIndex(array, item);\n return array[i] === item ? i : -1;\n }\n }\n if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item, isSorted);\n for (; i < length; i++) if (array[i] === item) return i;\n return -1;\n };\n\n // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.\n _.lastIndexOf = function(array, item, from) {\n if (array == null) return -1;\n var hasIndex = from != null;\n if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) {\n return hasIndex ? array.lastIndexOf(item, from) : array.lastIndexOf(item);\n }\n var i = (hasIndex ? from : array.length);\n while (i--) if (array[i] === item) return i;\n return -1;\n };\n\n // Generate an integer Array containing an arithmetic progression. A port of\n // the native Python `range()` function. See\n // [the Python documentation](http://docs.python.org/library/functions.html#range).\n _.range = function(start, stop, step) {\n if (arguments.length <= 1) {\n stop = start || 0;\n start = 0;\n }\n step = arguments[2] || 1;\n\n var length = Math.max(Math.ceil((stop - start) / step), 0);\n var idx = 0;\n var range = new Array(length);\n\n while(idx < length) {\n range[idx++] = start;\n start += step;\n }\n\n return range;\n };\n\n // Function (ahem) Functions\n // ------------------\n\n // Reusable constructor function for prototype setting.\n var ctor = function(){};\n\n // Create a function bound to a given object (assigning `this`, and arguments,\n // optionally). Delegates to **ECMAScript 5**'s native `Function.bind` if\n // available.\n _.bind = function(func, context) {\n var args, bound;\n if (nativeBind && func.bind === nativeBind) return nativeBind.apply(func, slice.call(arguments, 1));\n if (!_.isFunction(func)) throw new TypeError;\n args = slice.call(arguments, 2);\n return bound = function() {\n if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments)));\n ctor.prototype = func.prototype;\n var self = new ctor;\n ctor.prototype = null;\n var result = func.apply(self, args.concat(slice.call(arguments)));\n if (Object(result) === result) return result;\n return self;\n };\n };\n\n // Partially apply a function by creating a version that has had some of its\n // arguments pre-filled, without changing its dynamic `this` context.\n _.partial = function(func) {\n var args = slice.call(arguments, 1);\n return function() {\n return func.apply(this, args.concat(slice.call(arguments)));\n };\n };\n\n // Bind all of an object's methods to that object. Useful for ensuring that\n // all callbacks defined on an object belong to it.\n _.bindAll = function(obj) {\n var funcs = slice.call(arguments, 1);\n if (funcs.length === 0) throw new Error(\"bindAll must be passed function names\");\n each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });\n return obj;\n };\n\n // Memoize an expensive function by storing its results.\n _.memoize = function(func, hasher) {\n var memo = {};\n hasher || (hasher = _.identity);\n return function() {\n var key = hasher.apply(this, arguments);\n return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments));\n };\n };\n\n // Delays a function for the given number of milliseconds, and then calls\n // it with the arguments supplied.\n _.delay = function(func, wait) {\n var args = slice.call(arguments, 2);\n return setTimeout(function(){ return func.apply(null, args); }, wait);\n };\n\n // Defers a function, scheduling it to run after the current call stack has\n // cleared.\n _.defer = function(func) {\n return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));\n };\n\n // Returns a function, that, when invoked, will only be triggered at most once\n // during a given window of time. Normally, the throttled function will run\n // as much as it can, without ever going more than once per `wait` duration;\n // but if you'd like to disable the execution on the leading edge, pass\n // `{leading: false}`. To disable execution on the trailing edge, ditto.\n _.throttle = function(func, wait, options) {\n var context, args, result;\n var timeout = null;\n var previous = 0;\n options || (options = {});\n var later = function() {\n previous = options.leading === false ? 0 : new Date;\n timeout = null;\n result = func.apply(context, args);\n };\n return function() {\n var now = new Date;\n if (!previous && options.leading === false) previous = now;\n var remaining = wait - (now - previous);\n context = this;\n args = arguments;\n if (remaining <= 0) {\n clearTimeout(timeout);\n timeout = null;\n previous = now;\n result = func.apply(context, args);\n } else if (!timeout && options.trailing !== false) {\n timeout = setTimeout(later, remaining);\n }\n return result;\n };\n };\n\n // Returns a function, that, as long as it continues to be invoked, will not\n // be triggered. The function will be called after it stops being called for\n // N milliseconds. If `immediate` is passed, trigger the function on the\n // leading edge, instead of the trailing.\n _.debounce = function(func, wait, immediate) {\n var timeout, args, context, timestamp, result;\n return function() {\n context = this;\n args = arguments;\n timestamp = new Date();\n var later = function() {\n var last = (new Date()) - timestamp;\n if (last < wait) {\n timeout = setTimeout(later, wait - last);\n } else {\n timeout = null;\n if (!immediate) result = func.apply(context, args);\n }\n };\n var callNow = immediate && !timeout;\n if (!timeout) {\n timeout = setTimeout(later, wait);\n }\n if (callNow) result = func.apply(context, args);\n return result;\n };\n };\n\n // Returns a function that will be executed at most one time, no matter how\n // often you call it. Useful for lazy initialization.\n _.once = function(func) {\n var ran = false, memo;\n return function() {\n if (ran) return memo;\n ran = true;\n memo = func.apply(this, arguments);\n func = null;\n return memo;\n };\n };\n\n // Returns the first function passed as an argument to the second,\n // allowing you to adjust arguments, run code before and after, and\n // conditionally execute the original function.\n _.wrap = function(func, wrapper) {\n return function() {\n var args = [func];\n push.apply(args, arguments);\n return wrapper.apply(this, args);\n };\n };\n\n // Returns a function that is the composition of a list of functions, each\n // consuming the return value of the function that follows.\n _.compose = function() {\n var funcs = arguments;\n return function() {\n var args = arguments;\n for (var i = funcs.length - 1; i >= 0; i--) {\n args = [funcs[i].apply(this, args)];\n }\n return args[0];\n };\n };\n\n // Returns a function that will only be executed after being called N times.\n _.after = function(times, func) {\n return function() {\n if (--times < 1) {\n return func.apply(this, arguments);\n }\n };\n };\n\n // Object Functions\n // ----------------\n\n // Retrieve the names of an object's properties.\n // Delegates to **ECMAScript 5**'s native `Object.keys`\n _.keys = nativeKeys || function(obj) {\n if (obj !== Object(obj)) throw new TypeError('Invalid object');\n var keys = [];\n for (var key in obj) if (_.has(obj, key)) keys.push(key);\n return keys;\n };\n\n // Retrieve the values of an object's properties.\n _.values = function(obj) {\n var keys = _.keys(obj);\n var length = keys.length;\n var values = new Array(length);\n for (var i = 0; i < length; i++) {\n values[i] = obj[keys[i]];\n }\n return values;\n };\n\n // Convert an object into a list of `[key, value]` pairs.\n _.pairs = function(obj) {\n var keys = _.keys(obj);\n var length = keys.length;\n var pairs = new Array(length);\n for (var i = 0; i < length; i++) {\n pairs[i] = [keys[i], obj[keys[i]]];\n }\n return pairs;\n };\n\n // Invert the keys and values of an object. The values must be serializable.\n _.invert = function(obj) {\n var result = {};\n var keys = _.keys(obj);\n for (var i = 0, length = keys.length; i < length; i++) {\n result[obj[keys[i]]] = keys[i];\n }\n return result;\n };\n\n // Return a sorted list of the function names available on the object.\n // Aliased as `methods`\n _.functions = _.methods = function(obj) {\n var names = [];\n for (var key in obj) {\n if (_.isFunction(obj[key])) names.push(key);\n }\n return names.sort();\n };\n\n // Extend a given object with all the properties in passed-in object(s).\n _.extend = function(obj) {\n each(slice.call(arguments, 1), function(source) {\n if (source) {\n for (var prop in source) {\n obj[prop] = source[prop];\n }\n }\n });\n return obj;\n };\n\n // Return a copy of the object only containing the whitelisted properties.\n _.pick = function(obj) {\n var copy = {};\n var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n each(keys, function(key) {\n if (key in obj) copy[key] = obj[key];\n });\n return copy;\n };\n\n // Return a copy of the object without the blacklisted properties.\n _.omit = function(obj) {\n var copy = {};\n var keys = concat.apply(ArrayProto, slice.call(arguments, 1));\n for (var key in obj) {\n if (!_.contains(keys, key)) copy[key] = obj[key];\n }\n return copy;\n };\n\n // Fill in a given object with default properties.\n _.defaults = function(obj) {\n each(slice.call(arguments, 1), function(source) {\n if (source) {\n for (var prop in source) {\n if (obj[prop] === void 0) obj[prop] = source[prop];\n }\n }\n });\n return obj;\n };\n\n // Create a (shallow-cloned) duplicate of an object.\n _.clone = function(obj) {\n if (!_.isObject(obj)) return obj;\n return _.isArray(obj) ? obj.slice() : _.extend({}, obj);\n };\n\n // Invokes interceptor with the obj, and then returns obj.\n // The primary purpose of this method is to \"tap into\" a method chain, in\n // order to perform operations on intermediate results within the chain.\n _.tap = function(obj, interceptor) {\n interceptor(obj);\n return obj;\n };\n\n // Internal recursive comparison function for `isEqual`.\n var eq = function(a, b, aStack, bStack) {\n // Identical objects are equal. `0 === -0`, but they aren't identical.\n // See the [Harmony `egal` proposal](http://wiki.ecmascript.org/doku.php?id=harmony:egal).\n if (a === b) return a !== 0 || 1 / a == 1 / b;\n // A strict comparison is necessary because `null == undefined`.\n if (a == null || b == null) return a === b;\n // Unwrap any wrapped objects.\n if (a instanceof _) a = a._wrapped;\n if (b instanceof _) b = b._wrapped;\n // Compare `[[Class]]` names.\n var className = toString.call(a);\n if (className != toString.call(b)) return false;\n switch (className) {\n // Strings, numbers, dates, and booleans are compared by value.\n case '[object String]':\n // Primitives and their corresponding object wrappers are equivalent; thus, `\"5\"` is\n // equivalent to `new String(\"5\")`.\n return a == String(b);\n case '[object Number]':\n // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for\n // other numeric values.\n return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b);\n case '[object Date]':\n case '[object Boolean]':\n // Coerce dates and booleans to numeric primitive values. Dates are compared by their\n // millisecond representations. Note that invalid dates with millisecond representations\n // of `NaN` are not equivalent.\n return +a == +b;\n // RegExps are compared by their source patterns and flags.\n case '[object RegExp]':\n return a.source == b.source &&\n a.global == b.global &&\n a.multiline == b.multiline &&\n a.ignoreCase == b.ignoreCase;\n }\n if (typeof a != 'object' || typeof b != 'object') return false;\n // Assume equality for cyclic structures. The algorithm for detecting cyclic\n // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`.\n var length = aStack.length;\n while (length--) {\n // Linear search. Performance is inversely proportional to the number of\n // unique nested structures.\n if (aStack[length] == a) return bStack[length] == b;\n }\n // Objects with different constructors are not equivalent, but `Object`s\n // from different frames are.\n var aCtor = a.constructor, bCtor = b.constructor;\n if (aCtor !== bCtor && !(_.isFunction(aCtor) && (aCtor instanceof aCtor) &&\n _.isFunction(bCtor) && (bCtor instanceof bCtor))) {\n return false;\n }\n // Add the first object to the stack of traversed objects.\n aStack.push(a);\n bStack.push(b);\n var size = 0, result = true;\n // Recursively compare objects and arrays.\n if (className == '[object Array]') {\n // Compare array lengths to determine if a deep comparison is necessary.\n size = a.length;\n result = size == b.length;\n if (result) {\n // Deep compare the contents, ignoring non-numeric properties.\n while (size--) {\n if (!(result = eq(a[size], b[size], aStack, bStack))) break;\n }\n }\n } else {\n // Deep compare objects.\n for (var key in a) {\n if (_.has(a, key)) {\n // Count the expected number of properties.\n size++;\n // Deep compare each member.\n if (!(result = _.has(b, key) && eq(a[key], b[key], aStack, bStack))) break;\n }\n }\n // Ensure that both objects contain the same number of properties.\n if (result) {\n for (key in b) {\n if (_.has(b, key) && !(size--)) break;\n }\n result = !size;\n }\n }\n // Remove the first object from the stack of traversed objects.\n aStack.pop();\n bStack.pop();\n return result;\n };\n\n // Perform a deep comparison to check if two objects are equal.\n _.isEqual = function(a, b) {\n return eq(a, b, [], []);\n };\n\n // Is a given array, string, or object empty?\n // An \"empty\" object has no enumerable own-properties.\n _.isEmpty = function(obj) {\n if (obj == null) return true;\n if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;\n for (var key in obj) if (_.has(obj, key)) return false;\n return true;\n };\n\n // Is a given value a DOM element?\n _.isElement = function(obj) {\n return !!(obj && obj.nodeType === 1);\n };\n\n // Is a given value an array?\n // Delegates to ECMA5's native Array.isArray\n _.isArray = nativeIsArray || function(obj) {\n return toString.call(obj) == '[object Array]';\n };\n\n // Is a given variable an object?\n _.isObject = function(obj) {\n return obj === Object(obj);\n };\n\n // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp.\n each(['Arguments', 'Function', 'String', 'Number', 'Date', 'RegExp'], function(name) {\n _['is' + name] = function(obj) {\n return toString.call(obj) == '[object ' + name + ']';\n };\n });\n\n // Define a fallback version of the method in browsers (ahem, IE), where\n // there isn't any inspectable \"Arguments\" type.\n if (!_.isArguments(arguments)) {\n _.isArguments = function(obj) {\n return !!(obj && _.has(obj, 'callee'));\n };\n }\n\n // Optimize `isFunction` if appropriate.\n if (typeof (/./) !== 'function') {\n _.isFunction = function(obj) {\n return typeof obj === 'function';\n };\n }\n\n // Is a given object a finite number?\n _.isFinite = function(obj) {\n return isFinite(obj) && !isNaN(parseFloat(obj));\n };\n\n // Is the given value `NaN`? (NaN is the only number which does not equal itself).\n _.isNaN = function(obj) {\n return _.isNumber(obj) && obj != +obj;\n };\n\n // Is a given value a boolean?\n _.isBoolean = function(obj) {\n return obj === true || obj === false || toString.call(obj) == '[object Boolean]';\n };\n\n // Is a given value equal to null?\n _.isNull = function(obj) {\n return obj === null;\n };\n\n // Is a given variable undefined?\n _.isUndefined = function(obj) {\n return obj === void 0;\n };\n\n // Shortcut function for checking if an object has a given property directly\n // on itself (in other words, not on a prototype).\n _.has = function(obj, key) {\n return hasOwnProperty.call(obj, key);\n };\n\n // Utility Functions\n // -----------------\n\n // Run Underscore.js in *noConflict* mode, returning the `_` variable to its\n // previous owner. Returns a reference to the Underscore object.\n _.noConflict = function() {\n root._ = previousUnderscore;\n return this;\n };\n\n // Keep the identity function around for default iterators.\n _.identity = function(value) {\n return value;\n };\n\n // Run a function **n** times.\n _.times = function(n, iterator, context) {\n var accum = Array(Math.max(0, n));\n for (var i = 0; i < n; i++) accum[i] = iterator.call(context, i);\n return accum;\n };\n\n // Return a random integer between min and max (inclusive).\n _.random = function(min, max) {\n if (max == null) {\n max = min;\n min = 0;\n }\n return min + Math.floor(Math.random() * (max - min + 1));\n };\n\n // List of HTML entities for escaping.\n var entityMap = {\n escape: {\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }\n };\n entityMap.unescape = _.invert(entityMap.escape);\n\n // Regexes containing the keys and values listed immediately above.\n var entityRegexes = {\n escape: new RegExp('[' + _.keys(entityMap.escape).join('') + ']', 'g'),\n unescape: new RegExp('(' + _.keys(entityMap.unescape).join('|') + ')', 'g')\n };\n\n // Functions for escaping and unescaping strings to/from HTML interpolation.\n _.each(['escape', 'unescape'], function(method) {\n _[method] = function(string) {\n if (string == null) return '';\n return ('' + string).replace(entityRegexes[method], function(match) {\n return entityMap[method][match];\n });\n };\n });\n\n // If the value of the named `property` is a function then invoke it with the\n // `object` as context; otherwise, return it.\n _.result = function(object, property) {\n if (object == null) return void 0;\n var value = object[property];\n return _.isFunction(value) ? value.call(object) : value;\n };\n\n // Add your own custom functions to the Underscore object.\n _.mixin = function(obj) {\n each(_.functions(obj), function(name) {\n var func = _[name] = obj[name];\n _.prototype[name] = function() {\n var args = [this._wrapped];\n push.apply(args, arguments);\n return result.call(this, func.apply(_, args));\n };\n });\n };\n\n // Generate a unique integer id (unique within the entire client session).\n // Useful for temporary DOM ids.\n var idCounter = 0;\n _.uniqueId = function(prefix) {\n var id = ++idCounter + '';\n return prefix ? prefix + id : id;\n };\n\n // By default, Underscore uses ERB-style template delimiters, change the\n // following template settings to use alternative delimiters.\n _.templateSettings = {\n evaluate : /<%([\\s\\S]+?)%>/g,\n interpolate : /<%=([\\s\\S]+?)%>/g,\n escape : /<%-([\\s\\S]+?)%>/g\n };\n\n // When customizing `templateSettings`, if you don't want to define an\n // interpolation, evaluation or escaping regex, we need one that is\n // guaranteed not to match.\n var noMatch = /(.)^/;\n\n // Certain characters need to be escaped so that they can be put into a\n // string literal.\n var escapes = {\n \"'\": \"'\",\n '\\\\': '\\\\',\n '\\r': 'r',\n '\\n': 'n',\n '\\t': 't',\n '\\u2028': 'u2028',\n '\\u2029': 'u2029'\n };\n\n var escaper = /\\\\|'|\\r|\\n|\\t|\\u2028|\\u2029/g;\n\n // JavaScript micro-templating, similar to John Resig's implementation.\n // Underscore templating handles arbitrary delimiters, preserves whitespace,\n // and correctly escapes quotes within interpolated code.\n _.template = function(text, data, settings) {\n var render;\n settings = _.defaults({}, settings, _.templateSettings);\n\n // Combine delimiters into one regular expression via alternation.\n var matcher = new RegExp([\n (settings.escape || noMatch).source,\n (settings.interpolate || noMatch).source,\n (settings.evaluate || noMatch).source\n ].join('|') + '|$', 'g');\n\n // Compile the template source, escaping string literals appropriately.\n var index = 0;\n var source = \"__p+='\";\n text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {\n source += text.slice(index, offset)\n .replace(escaper, function(match) { return '\\\\' + escapes[match]; });\n\n if (escape) {\n source += \"'+\\n((__t=(\" + escape + \"))==null?'':_.escape(__t))+\\n'\";\n }\n if (interpolate) {\n source += \"'+\\n((__t=(\" + interpolate + \"))==null?'':__t)+\\n'\";\n }\n if (evaluate) {\n source += \"';\\n\" + evaluate + \"\\n__p+='\";\n }\n index = offset + match.length;\n return match;\n });\n source += \"';\\n\";\n\n // If a variable is not specified, place data values in local scope.\n if (!settings.variable) source = 'with(obj||{}){\\n' + source + '}\\n';\n\n source = \"var __t,__p='',__j=Array.prototype.join,\" +\n \"print=function(){__p+=__j.call(arguments,'');};\\n\" +\n source + \"return __p;\\n\";\n\n try {\n render = new Function(settings.variable || 'obj', '_', source);\n } catch (e) {\n e.source = source;\n throw e;\n }\n\n if (data) return render(data, _);\n var template = function(data) {\n return render.call(this, data, _);\n };\n\n // Provide the compiled function source as a convenience for precompilation.\n template.source = 'function(' + (settings.variable || 'obj') + '){\\n' + source + '}';\n\n return template;\n };\n\n // Add a \"chain\" function, which will delegate to the wrapper.\n _.chain = function(obj) {\n return _(obj).chain();\n };\n\n // OOP\n // ---------------\n // If Underscore is called as a function, it returns a wrapped object that\n // can be used OO-style. This wrapper holds altered versions of all the\n // underscore functions. Wrapped objects may be chained.\n\n // Helper function to continue chaining intermediate results.\n var result = function(obj) {\n return this._chain ? _(obj).chain() : obj;\n };\n\n // Add all of the Underscore functions to the wrapper object.\n _.mixin(_);\n\n // Add all mutator Array functions to the wrapper.\n each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {\n var method = ArrayProto[name];\n _.prototype[name] = function() {\n var obj = this._wrapped;\n method.apply(obj, arguments);\n if ((name == 'shift' || name == 'splice') && obj.length === 0) delete obj[0];\n return result.call(this, obj);\n };\n });\n\n // Add all accessor Array functions to the wrapper.\n each(['concat', 'join', 'slice'], function(name) {\n var method = ArrayProto[name];\n _.prototype[name] = function() {\n return result.call(this, method.apply(this._wrapped, arguments));\n };\n });\n\n _.extend(_.prototype, {\n\n // Start chaining a wrapped Underscore object.\n chain: function() {\n this._chain = true;\n return this;\n },\n\n // Extracts the result from a wrapped and chained object.\n value: function() {\n return this._wrapped;\n }\n\n });\n\n}).call(this);\n\n},{}],4:[function(require,module,exports){\n// MarionetteJS (Backbone.Marionette)\n// ----------------------------------\n// v2.4.3\n//\n// Copyright (c)2015 Derick Bailey, Muted Solutions, LLC.\n// Distributed under MIT license\n//\n// http://marionettejs.com\n\n(function(root, factory) {\n\n if (typeof define === 'function' && define.amd) {\n define(['backbone', 'underscore', 'backbone.wreqr', 'backbone.babysitter'], function(Backbone, _) {\n return (root.Marionette = root.Mn = factory(root, Backbone, _));\n });\n } else if (typeof exports !== 'undefined') {\n var Backbone = require('backbone');\n var _ = require('underscore');\n var Wreqr = require('backbone.wreqr');\n var BabySitter = require('backbone.babysitter');\n module.exports = factory(root, Backbone, _);\n } else {\n root.Marionette = root.Mn = factory(root, root.Backbone, root._);\n }\n\n}(this, function(root, Backbone, _) {\n 'use strict';\n\n var previousMarionette = root.Marionette;\n var previousMn = root.Mn;\n\n var Marionette = Backbone.Marionette = {};\n\n Marionette.VERSION = '2.4.3';\n\n Marionette.noConflict = function() {\n root.Marionette = previousMarionette;\n root.Mn = previousMn;\n return this;\n };\n\n // Get the Deferred creator for later use\n Marionette.Deferred = Backbone.$.Deferred;\n\n Marionette.FEATURES = {\n };\n \n Marionette.isEnabled = function(name) {\n return !!Marionette.FEATURES[name];\n };\n \n /* jshint unused: false *//* global console */\n \n // Helpers\n // -------\n \n // Marionette.extend\n // -----------------\n \n // Borrow the Backbone `extend` method so we can use it as needed\n Marionette.extend = Backbone.Model.extend;\n \n // Marionette.isNodeAttached\n // -------------------------\n \n // Determine if `el` is a child of the document\n Marionette.isNodeAttached = function(el) {\n return Backbone.$.contains(document.documentElement, el);\n };\n \n // Merge `keys` from `options` onto `this`\n Marionette.mergeOptions = function(options, keys) {\n if (!options) { return; }\n _.extend(this, _.pick(options, keys));\n };\n \n // Marionette.getOption\n // --------------------\n \n // Retrieve an object, function or other value from a target\n // object or its `options`, with `options` taking precedence.\n Marionette.getOption = function(target, optionName) {\n if (!target || !optionName) { return; }\n if (target.options && (target.options[optionName] !== undefined)) {\n return target.options[optionName];\n } else {\n return target[optionName];\n }\n };\n \n // Proxy `Marionette.getOption`\n Marionette.proxyGetOption = function(optionName) {\n return Marionette.getOption(this, optionName);\n };\n \n // Similar to `_.result`, this is a simple helper\n // If a function is provided we call it with context\n // otherwise just return the value. If the value is\n // undefined return a default value\n Marionette._getValue = function(value, context, params) {\n if (_.isFunction(value)) {\n value = params ? value.apply(context, params) : value.call(context);\n }\n return value;\n };\n \n // Marionette.normalizeMethods\n // ----------------------\n \n // Pass in a mapping of events => functions or function names\n // and return a mapping of events => functions\n Marionette.normalizeMethods = function(hash) {\n return _.reduce(hash, function(normalizedHash, method, name) {\n if (!_.isFunction(method)) {\n method = this[method];\n }\n if (method) {\n normalizedHash[name] = method;\n }\n return normalizedHash;\n }, {}, this);\n };\n \n // utility method for parsing @ui. syntax strings\n // into associated selector\n Marionette.normalizeUIString = function(uiString, ui) {\n return uiString.replace(/@ui\\.[a-zA-Z_$0-9]*/g, function(r) {\n return ui[r.slice(4)];\n });\n };\n \n // allows for the use of the @ui. syntax within\n // a given key for triggers and events\n // swaps the @ui with the associated selector.\n // Returns a new, non-mutated, parsed events hash.\n Marionette.normalizeUIKeys = function(hash, ui) {\n return _.reduce(hash, function(memo, val, key) {\n var normalizedKey = Marionette.normalizeUIString(key, ui);\n memo[normalizedKey] = val;\n return memo;\n }, {});\n };\n \n // allows for the use of the @ui. syntax within\n // a given value for regions\n // swaps the @ui with the associated selector\n Marionette.normalizeUIValues = function(hash, ui, properties) {\n _.each(hash, function(val, key) {\n if (_.isString(val)) {\n hash[key] = Marionette.normalizeUIString(val, ui);\n } else if (_.isObject(val) && _.isArray(properties)) {\n _.extend(val, Marionette.normalizeUIValues(_.pick(val, properties), ui));\n /* Value is an object, and we got an array of embedded property names to normalize. */\n _.each(properties, function(property) {\n var propertyVal = val[property];\n if (_.isString(propertyVal)) {\n val[property] = Marionette.normalizeUIString(propertyVal, ui);\n }\n });\n }\n });\n return hash;\n };\n \n // Mix in methods from Underscore, for iteration, and other\n // collection related features.\n // Borrowing this code from Backbone.Collection:\n // http://backbonejs.org/docs/backbone.html#section-121\n Marionette.actAsCollection = function(object, listProperty) {\n var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',\n 'select', 'reject', 'every', 'all', 'some', 'any', 'include',\n 'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',\n 'last', 'without', 'isEmpty', 'pluck'];\n \n _.each(methods, function(method) {\n object[method] = function() {\n var list = _.values(_.result(this, listProperty));\n var args = [list].concat(_.toArray(arguments));\n return _[method].apply(_, args);\n };\n });\n };\n \n var deprecate = Marionette.deprecate = function(message, test) {\n if (_.isObject(message)) {\n message = (\n message.prev + ' is going to be removed in the future. ' +\n 'Please use ' + message.next + ' instead.' +\n (message.url ? ' See: ' + message.url : '')\n );\n }\n \n if ((test === undefined || !test) && !deprecate._cache[message]) {\n deprecate._warn('Deprecation warning: ' + message);\n deprecate._cache[message] = true;\n }\n };\n \n deprecate._warn = typeof console !== 'undefined' && (console.warn || console.log) || function() {};\n deprecate._cache = {};\n \n /* jshint maxstatements: 14, maxcomplexity: 7 */\n \n // Trigger Method\n // --------------\n \n Marionette._triggerMethod = (function() {\n // split the event name on the \":\"\n var splitter = /(^|:)(\\w)/gi;\n \n // take the event section (\"section1:section2:section3\")\n // and turn it in to uppercase name\n function getEventName(match, prefix, eventName) {\n return eventName.toUpperCase();\n }\n \n return function(context, event, args) {\n var noEventArg = arguments.length < 3;\n if (noEventArg) {\n args = event;\n event = args[0];\n }\n \n // get the method name from the event name\n var methodName = 'on' + event.replace(splitter, getEventName);\n var method = context[methodName];\n var result;\n \n // call the onMethodName if it exists\n if (_.isFunction(method)) {\n // pass all args, except the event name\n result = method.apply(context, noEventArg ? _.rest(args) : args);\n }\n \n // trigger the event, if a trigger method exists\n if (_.isFunction(context.trigger)) {\n if (noEventArg + args.length > 1) {\n context.trigger.apply(context, noEventArg ? args : [event].concat(_.drop(args, 0)));\n } else {\n context.trigger(event);\n }\n }\n \n return result;\n };\n })();\n \n // Trigger an event and/or a corresponding method name. Examples:\n //\n // `this.triggerMethod(\"foo\")` will trigger the \"foo\" event and\n // call the \"onFoo\" method.\n //\n // `this.triggerMethod(\"foo:bar\")` will trigger the \"foo:bar\" event and\n // call the \"onFooBar\" method.\n Marionette.triggerMethod = function(event) {\n return Marionette._triggerMethod(this, arguments);\n };\n \n // triggerMethodOn invokes triggerMethod on a specific context\n //\n // e.g. `Marionette.triggerMethodOn(view, 'show')`\n // will trigger a \"show\" event or invoke onShow the view.\n Marionette.triggerMethodOn = function(context) {\n var fnc = _.isFunction(context.triggerMethod) ?\n context.triggerMethod :\n Marionette.triggerMethod;\n \n return fnc.apply(context, _.rest(arguments));\n };\n \n // DOM Refresh\n // -----------\n \n // Monitor a view's state, and after it has been rendered and shown\n // in the DOM, trigger a \"dom:refresh\" event every time it is\n // re-rendered.\n \n Marionette.MonitorDOMRefresh = function(view) {\n if (view._isDomRefreshMonitored) { return; }\n view._isDomRefreshMonitored = true;\n \n // track when the view has been shown in the DOM,\n // using a Marionette.Region (or by other means of triggering \"show\")\n function handleShow() {\n view._isShown = true;\n triggerDOMRefresh();\n }\n \n // track when the view has been rendered\n function handleRender() {\n view._isRendered = true;\n triggerDOMRefresh();\n }\n \n // Trigger the \"dom:refresh\" event and corresponding \"onDomRefresh\" method\n function triggerDOMRefresh() {\n if (view._isShown && view._isRendered && Marionette.isNodeAttached(view.el)) {\n Marionette.triggerMethodOn(view, 'dom:refresh', view);\n }\n }\n \n view.on({\n show: handleShow,\n render: handleRender\n });\n };\n \n /* jshint maxparams: 5 */\n \n // Bind Entity Events & Unbind Entity Events\n // -----------------------------------------\n //\n // These methods are used to bind/unbind a backbone \"entity\" (e.g. collection/model)\n // to methods on a target object.\n //\n // The first parameter, `target`, must have the Backbone.Events module mixed in.\n //\n // The second parameter is the `entity` (Backbone.Model, Backbone.Collection or\n // any object that has Backbone.Events mixed in) to bind the events from.\n //\n // The third parameter is a hash of { \"event:name\": \"eventHandler\" }\n // configuration. Multiple handlers can be separated by a space. A\n // function can be supplied instead of a string handler name.\n \n (function(Marionette) {\n 'use strict';\n \n // Bind the event to handlers specified as a string of\n // handler names on the target object\n function bindFromStrings(target, entity, evt, methods) {\n var methodNames = methods.split(/\\s+/);\n \n _.each(methodNames, function(methodName) {\n \n var method = target[methodName];\n if (!method) {\n throw new Marionette.Error('Method \"' + methodName +\n '\" was configured as an event handler, but does not exist.');\n }\n \n target.listenTo(entity, evt, method);\n });\n }\n \n // Bind the event to a supplied callback function\n function bindToFunction(target, entity, evt, method) {\n target.listenTo(entity, evt, method);\n }\n \n // Bind the event to handlers specified as a string of\n // handler names on the target object\n function unbindFromStrings(target, entity, evt, methods) {\n var methodNames = methods.split(/\\s+/);\n \n _.each(methodNames, function(methodName) {\n var method = target[methodName];\n target.stopListening(entity, evt, method);\n });\n }\n \n // Bind the event to a supplied callback function\n function unbindToFunction(target, entity, evt, method) {\n target.stopListening(entity, evt, method);\n }\n \n // generic looping function\n function iterateEvents(target, entity, bindings, functionCallback, stringCallback) {\n if (!entity || !bindings) { return; }\n \n // type-check bindings\n if (!_.isObject(bindings)) {\n throw new Marionette.Error({\n message: 'Bindings must be an object or function.',\n url: 'marionette.functions.html#marionettebindentityevents'\n });\n }\n \n // allow the bindings to be a function\n bindings = Marionette._getValue(bindings, target);\n \n // iterate the bindings and bind them\n _.each(bindings, function(methods, evt) {\n \n // allow for a function as the handler,\n // or a list of event names as a string\n if (_.isFunction(methods)) {\n functionCallback(target, entity, evt, methods);\n } else {\n stringCallback(target, entity, evt, methods);\n }\n \n });\n }\n \n // Export Public API\n Marionette.bindEntityEvents = function(target, entity, bindings) {\n iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings);\n };\n \n Marionette.unbindEntityEvents = function(target, entity, bindings) {\n iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings);\n };\n \n // Proxy `bindEntityEvents`\n Marionette.proxyBindEntityEvents = function(entity, bindings) {\n return Marionette.bindEntityEvents(this, entity, bindings);\n };\n \n // Proxy `unbindEntityEvents`\n Marionette.proxyUnbindEntityEvents = function(entity, bindings) {\n return Marionette.unbindEntityEvents(this, entity, bindings);\n };\n })(Marionette);\n \n\n // Error\n // -----\n \n var errorProps = ['description', 'fileName', 'lineNumber', 'name', 'message', 'number'];\n \n Marionette.Error = Marionette.extend.call(Error, {\n urlRoot: 'http://marionettejs.com/docs/v' + Marionette.VERSION + '/',\n \n constructor: function(message, options) {\n if (_.isObject(message)) {\n options = message;\n message = options.message;\n } else if (!options) {\n options = {};\n }\n \n var error = Error.call(this, message);\n _.extend(this, _.pick(error, errorProps), _.pick(options, errorProps));\n \n this.captureStackTrace();\n \n if (options.url) {\n this.url = this.urlRoot + options.url;\n }\n },\n \n captureStackTrace: function() {\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, Marionette.Error);\n }\n },\n \n toString: function() {\n return this.name + ': ' + this.message + (this.url ? ' See: ' + this.url : '');\n }\n });\n \n Marionette.Error.extend = Marionette.extend;\n \n // Callbacks\n // ---------\n \n // A simple way of managing a collection of callbacks\n // and executing them at a later point in time, using jQuery's\n // `Deferred` object.\n Marionette.Callbacks = function() {\n this._deferred = Marionette.Deferred();\n this._callbacks = [];\n };\n \n _.extend(Marionette.Callbacks.prototype, {\n \n // Add a callback to be executed. Callbacks added here are\n // guaranteed to execute, even if they are added after the\n // `run` method is called.\n add: function(callback, contextOverride) {\n var promise = _.result(this._deferred, 'promise');\n \n this._callbacks.push({cb: callback, ctx: contextOverride});\n \n promise.then(function(args) {\n if (contextOverride) { args.context = contextOverride; }\n callback.call(args.context, args.options);\n });\n },\n \n // Run all registered callbacks with the context specified.\n // Additional callbacks can be added after this has been run\n // and they will still be executed.\n run: function(options, context) {\n this._deferred.resolve({\n options: options,\n context: context\n });\n },\n \n // Resets the list of callbacks to be run, allowing the same list\n // to be run multiple times - whenever the `run` method is called.\n reset: function() {\n var callbacks = this._callbacks;\n this._deferred = Marionette.Deferred();\n this._callbacks = [];\n \n _.each(callbacks, function(cb) {\n this.add(cb.cb, cb.ctx);\n }, this);\n }\n });\n \n // Controller\n // ----------\n \n // A multi-purpose object to use as a controller for\n // modules and routers, and as a mediator for workflow\n // and coordination of other objects, views, and more.\n Marionette.Controller = function(options) {\n this.options = options || {};\n \n if (_.isFunction(this.initialize)) {\n this.initialize(this.options);\n }\n };\n \n Marionette.Controller.extend = Marionette.extend;\n \n // Controller Methods\n // --------------\n \n // Ensure it can trigger events with Backbone.Events\n _.extend(Marionette.Controller.prototype, Backbone.Events, {\n destroy: function() {\n Marionette._triggerMethod(this, 'before:destroy', arguments);\n Marionette._triggerMethod(this, 'destroy', arguments);\n \n this.stopListening();\n this.off();\n return this;\n },\n \n // import the `triggerMethod` to trigger events with corresponding\n // methods if the method exists\n triggerMethod: Marionette.triggerMethod,\n \n // A handy way to merge options onto the instance\n mergeOptions: Marionette.mergeOptions,\n \n // Proxy `getOption` to enable getting options from this or this.options by name.\n getOption: Marionette.proxyGetOption\n \n });\n \n // Object\n // ------\n \n // A Base Class that other Classes should descend from.\n // Object borrows many conventions and utilities from Backbone.\n Marionette.Object = function(options) {\n this.options = _.extend({}, _.result(this, 'options'), options);\n \n this.initialize.apply(this, arguments);\n };\n \n Marionette.Object.extend = Marionette.extend;\n \n // Object Methods\n // --------------\n \n // Ensure it can trigger events with Backbone.Events\n _.extend(Marionette.Object.prototype, Backbone.Events, {\n \n //this is a noop method intended to be overridden by classes that extend from this base\n initialize: function() {},\n \n destroy: function() {\n this.triggerMethod('before:destroy');\n this.triggerMethod('destroy');\n this.stopListening();\n \n return this;\n },\n \n // Import the `triggerMethod` to trigger events with corresponding\n // methods if the method exists\n triggerMethod: Marionette.triggerMethod,\n \n // A handy way to merge options onto the instance\n mergeOptions: Marionette.mergeOptions,\n \n // Proxy `getOption` to enable getting options from this or this.options by name.\n getOption: Marionette.proxyGetOption,\n \n // Proxy `bindEntityEvents` to enable binding view's events from another entity.\n bindEntityEvents: Marionette.proxyBindEntityEvents,\n \n // Proxy `unbindEntityEvents` to enable unbinding view's events from another entity.\n unbindEntityEvents: Marionette.proxyUnbindEntityEvents\n });\n \n /* jshint maxcomplexity: 16, maxstatements: 45, maxlen: 120 */\n \n // Region\n // ------\n \n // Manage the visual regions of your composite application. See\n // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/\n \n Marionette.Region = Marionette.Object.extend({\n constructor: function(options) {\n \n // set options temporarily so that we can get `el`.\n // options will be overriden by Object.constructor\n this.options = options || {};\n this.el = this.getOption('el');\n \n // Handle when this.el is passed in as a $ wrapped element.\n this.el = this.el instanceof Backbone.$ ? this.el[0] : this.el;\n \n if (!this.el) {\n throw new Marionette.Error({\n name: 'NoElError',\n message: 'An \"el\" must be specified for a region.'\n });\n }\n \n this.$el = this.getEl(this.el);\n Marionette.Object.call(this, options);\n },\n \n // Displays a backbone view instance inside of the region.\n // Handles calling the `render` method for you. Reads content\n // directly from the `el` attribute. Also calls an optional\n // `onShow` and `onDestroy` method on your view, just after showing\n // or just before destroying the view, respectively.\n // The `preventDestroy` option can be used to prevent a view from\n // the old view being destroyed on show.\n // The `forceShow` option can be used to force a view to be\n // re-rendered if it's already shown in the region.\n show: function(view, options) {\n if (!this._ensureElement()) {\n return;\n }\n \n this._ensureViewIsIntact(view);\n Marionette.MonitorDOMRefresh(view);\n \n var showOptions = options || {};\n var isDifferentView = view !== this.currentView;\n var preventDestroy = !!showOptions.preventDestroy;\n var forceShow = !!showOptions.forceShow;\n \n // We are only changing the view if there is a current view to change to begin with\n var isChangingView = !!this.currentView;\n \n // Only destroy the current view if we don't want to `preventDestroy` and if\n // the view given in the first argument is different than `currentView`\n var _shouldDestroyView = isDifferentView && !preventDestroy;\n \n // Only show the view given in the first argument if it is different than\n // the current view or if we want to re-show the view. Note that if\n // `_shouldDestroyView` is true, then `_shouldShowView` is also necessarily true.\n var _shouldShowView = isDifferentView || forceShow;\n \n if (isChangingView) {\n this.triggerMethod('before:swapOut', this.currentView, this, options);\n }\n \n if (this.currentView) {\n delete this.currentView._parent;\n }\n \n if (_shouldDestroyView) {\n this.empty();\n \n // A `destroy` event is attached to the clean up manually removed views.\n // We need to detach this event when a new view is going to be shown as it\n // is no longer relevant.\n } else if (isChangingView && _shouldShowView) {\n this.currentView.off('destroy', this.empty, this);\n }\n \n if (_shouldShowView) {\n \n // We need to listen for if a view is destroyed\n // in a way other than through the region.\n // If this happens we need to remove the reference\n // to the currentView since once a view has been destroyed\n // we can not reuse it.\n view.once('destroy', this.empty, this);\n \n this._renderView(view);\n \n view._parent = this;\n \n if (isChangingView) {\n this.triggerMethod('before:swap', view, this, options);\n }\n \n this.triggerMethod('before:show', view, this, options);\n Marionette.triggerMethodOn(view, 'before:show', view, this, options);\n \n if (isChangingView) {\n this.triggerMethod('swapOut', this.currentView, this, options);\n }\n \n // An array of views that we're about to display\n var attachedRegion = Marionette.isNodeAttached(this.el);\n \n // The views that we're about to attach to the document\n // It's important that we prevent _getNestedViews from being executed unnecessarily\n // as it's a potentially-slow method\n var displayedViews = [];\n \n var attachOptions = _.extend({\n triggerBeforeAttach: this.triggerBeforeAttach,\n triggerAttach: this.triggerAttach\n }, showOptions);\n \n if (attachedRegion && attachOptions.triggerBeforeAttach) {\n displayedViews = this._displayedViews(view);\n this._triggerAttach(displayedViews, 'before:');\n }\n \n this.attachHtml(view);\n this.currentView = view;\n \n if (attachedRegion && attachOptions.triggerAttach) {\n displayedViews = this._displayedViews(view);\n this._triggerAttach(displayedViews);\n }\n \n if (isChangingView) {\n this.triggerMethod('swap', view, this, options);\n }\n \n this.triggerMethod('show', view, this, options);\n Marionette.triggerMethodOn(view, 'show', view, this, options);\n \n return this;\n }\n \n return this;\n },\n \n triggerBeforeAttach: true,\n triggerAttach: true,\n \n _triggerAttach: function(views, prefix) {\n var eventName = (prefix || '') + 'attach';\n _.each(views, function(view) {\n Marionette.triggerMethodOn(view, eventName, view, this);\n }, this);\n },\n \n _displayedViews: function(view) {\n return _.union([view], _.result(view, '_getNestedViews') || []);\n },\n \n _renderView: function(view) {\n if (!view.supportsRenderLifecycle) {\n Marionette.triggerMethodOn(view, 'before:render', view);\n }\n view.render();\n if (!view.supportsRenderLifecycle) {\n Marionette.triggerMethodOn(view, 'render', view);\n }\n },\n \n _ensureElement: function() {\n if (!_.isObject(this.el)) {\n this.$el = this.getEl(this.el);\n this.el = this.$el[0];\n }\n \n if (!this.$el || this.$el.length === 0) {\n if (this.getOption('allowMissingEl')) {\n return false;\n } else {\n throw new Marionette.Error('An \"el\" ' + this.$el.selector + ' must exist in DOM');\n }\n }\n return true;\n },\n \n _ensureViewIsIntact: function(view) {\n if (!view) {\n throw new Marionette.Error({\n name: 'ViewNotValid',\n message: 'The view passed is undefined and therefore invalid. You must pass a view instance to show.'\n });\n }\n \n if (view.isDestroyed) {\n throw new Marionette.Error({\n name: 'ViewDestroyedError',\n message: 'View (cid: \"' + view.cid + '\") has already been destroyed and cannot be used.'\n });\n }\n },\n \n // Override this method to change how the region finds the DOM\n // element that it manages. Return a jQuery selector object scoped\n // to a provided parent el or the document if none exists.\n getEl: function(el) {\n return Backbone.$(el, Marionette._getValue(this.options.parentEl, this));\n },\n \n // Override this method to change how the new view is\n // appended to the `$el` that the region is managing\n attachHtml: function(view) {\n this.$el.contents().detach();\n \n this.el.appendChild(view.el);\n },\n \n // Destroy the current view, if there is one. If there is no\n // current view, it does nothing and returns immediately.\n empty: function(options) {\n var view = this.currentView;\n \n var emptyOptions = options || {};\n var preventDestroy = !!emptyOptions.preventDestroy;\n // If there is no view in the region\n // we should not remove anything\n if (!view) { return; }\n \n view.off('destroy', this.empty, this);\n this.triggerMethod('before:empty', view);\n if (!preventDestroy) {\n this._destroyView();\n }\n this.triggerMethod('empty', view);\n \n // Remove region pointer to the currentView\n delete this.currentView;\n \n if (preventDestroy) {\n this.$el.contents().detach();\n }\n \n return this;\n },\n \n // call 'destroy' or 'remove', depending on which is found\n // on the view (if showing a raw Backbone view or a Marionette View)\n _destroyView: function() {\n var view = this.currentView;\n if (view.isDestroyed) { return; }\n \n if (!view.supportsDestroyLifecycle) {\n Marionette.triggerMethodOn(view, 'before:destroy', view);\n }\n if (view.destroy) {\n view.destroy();\n } else {\n view.remove();\n \n // appending isDestroyed to raw Backbone View allows regions\n // to throw a ViewDestroyedError for this view\n view.isDestroyed = true;\n }\n if (!view.supportsDestroyLifecycle) {\n Marionette.triggerMethodOn(view, 'destroy', view);\n }\n },\n \n // Attach an existing view to the region. This\n // will not call `render` or `onShow` for the new view,\n // and will not replace the current HTML for the `el`\n // of the region.\n attachView: function(view) {\n if (this.currentView) {\n delete this.currentView._parent;\n }\n view._parent = this;\n this.currentView = view;\n return this;\n },\n \n // Checks whether a view is currently present within\n // the region. Returns `true` if there is and `false` if\n // no view is present.\n hasView: function() {\n return !!this.currentView;\n },\n \n // Reset the region by destroying any existing view and\n // clearing out the cached `$el`. The next time a view\n // is shown via this region, the region will re-query the\n // DOM for the region's `el`.\n reset: function() {\n this.empty();\n \n if (this.$el) {\n this.el = this.$el.selector;\n }\n \n delete this.$el;\n return this;\n }\n \n },\n \n // Static Methods\n {\n \n // Build an instance of a region by passing in a configuration object\n // and a default region class to use if none is specified in the config.\n //\n // The config object should either be a string as a jQuery DOM selector,\n // a Region class directly, or an object literal that specifies a selector,\n // a custom regionClass, and any options to be supplied to the region:\n //\n // ```js\n // {\n // selector: \"#foo\",\n // regionClass: MyCustomRegion,\n // allowMissingEl: false\n // }\n // ```\n //\n buildRegion: function(regionConfig, DefaultRegionClass) {\n if (_.isString(regionConfig)) {\n return this._buildRegionFromSelector(regionConfig, DefaultRegionClass);\n }\n \n if (regionConfig.selector || regionConfig.el || regionConfig.regionClass) {\n return this._buildRegionFromObject(regionConfig, DefaultRegionClass);\n }\n \n if (_.isFunction(regionConfig)) {\n return this._buildRegionFromRegionClass(regionConfig);\n }\n \n throw new Marionette.Error({\n message: 'Improper region configuration type.',\n url: 'marionette.region.html#region-configuration-types'\n });\n },\n \n // Build the region from a string selector like '#foo-region'\n _buildRegionFromSelector: function(selector, DefaultRegionClass) {\n return new DefaultRegionClass({el: selector});\n },\n \n // Build the region from a configuration object\n // ```js\n // { selector: '#foo', regionClass: FooRegion, allowMissingEl: false }\n // ```\n _buildRegionFromObject: function(regionConfig, DefaultRegionClass) {\n var RegionClass = regionConfig.regionClass || DefaultRegionClass;\n var options = _.omit(regionConfig, 'selector', 'regionClass');\n \n if (regionConfig.selector && !options.el) {\n options.el = regionConfig.selector;\n }\n \n return new RegionClass(options);\n },\n \n // Build the region directly from a given `RegionClass`\n _buildRegionFromRegionClass: function(RegionClass) {\n return new RegionClass();\n }\n });\n \n // Region Manager\n // --------------\n \n // Manage one or more related `Marionette.Region` objects.\n Marionette.RegionManager = Marionette.Controller.extend({\n constructor: function(options) {\n this._regions = {};\n this.length = 0;\n \n Marionette.Controller.call(this, options);\n \n this.addRegions(this.getOption('regions'));\n },\n \n // Add multiple regions using an object literal or a\n // function that returns an object literal, where\n // each key becomes the region name, and each value is\n // the region definition.\n addRegions: function(regionDefinitions, defaults) {\n regionDefinitions = Marionette._getValue(regionDefinitions, this, arguments);\n \n return _.reduce(regionDefinitions, function(regions, definition, name) {\n if (_.isString(definition)) {\n definition = {selector: definition};\n }\n if (definition.selector) {\n definition = _.defaults({}, definition, defaults);\n }\n \n regions[name] = this.addRegion(name, definition);\n return regions;\n }, {}, this);\n },\n \n // Add an individual region to the region manager,\n // and return the region instance\n addRegion: function(name, definition) {\n var region;\n \n if (definition instanceof Marionette.Region) {\n region = definition;\n } else {\n region = Marionette.Region.buildRegion(definition, Marionette.Region);\n }\n \n this.triggerMethod('before:add:region', name, region);\n \n region._parent = this;\n this._store(name, region);\n \n this.triggerMethod('add:region', name, region);\n return region;\n },\n \n // Get a region by name\n get: function(name) {\n return this._regions[name];\n },\n \n // Gets all the regions contained within\n // the `regionManager` instance.\n getRegions: function() {\n return _.clone(this._regions);\n },\n \n // Remove a region by name\n removeRegion: function(name) {\n var region = this._regions[name];\n this._remove(name, region);\n \n return region;\n },\n \n // Empty all regions in the region manager, and\n // remove them\n removeRegions: function() {\n var regions = this.getRegions();\n _.each(this._regions, function(region, name) {\n this._remove(name, region);\n }, this);\n \n return regions;\n },\n \n // Empty all regions in the region manager, but\n // leave them attached\n emptyRegions: function() {\n var regions = this.getRegions();\n _.invoke(regions, 'empty');\n return regions;\n },\n \n // Destroy all regions and shut down the region\n // manager entirely\n destroy: function() {\n this.removeRegions();\n return Marionette.Controller.prototype.destroy.apply(this, arguments);\n },\n \n // internal method to store regions\n _store: function(name, region) {\n if (!this._regions[name]) {\n this.length++;\n }\n \n this._regions[name] = region;\n },\n \n // internal method to remove a region\n _remove: function(name, region) {\n this.triggerMethod('before:remove:region', name, region);\n region.empty();\n region.stopListening();\n \n delete region._parent;\n delete this._regions[name];\n this.length--;\n this.triggerMethod('remove:region', name, region);\n }\n });\n \n Marionette.actAsCollection(Marionette.RegionManager.prototype, '_regions');\n \n\n // Template Cache\n // --------------\n \n // Manage templates stored in `