// Backbone.Marionette, v1.0.0-rc5
// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
// Distributed under MIT license
// http://github.com/marionettejs/backbone.marionette


/*!
 * Includes BabySitter
 * https://github.com/marionettejs/backbone.babysitter/
 *
 * Includes Wreqr
 * https://github.com/marionettejs/backbone.wreqr/
 */


// Backbone.BabySitter, v0.0.4
// Copyright (c)2012 Derick Bailey, Muted Solutions, LLC.
// Distributed under MIT license
// http://github.com/marionettejs/backbone.babysitter
// Backbone.ChildViewContainer
// ---------------------------
//
// Provide a container to store, retrieve and
// shut down child views.

Backbone.ChildViewContainer = (function (Backbone, _) {

    // Container Constructor
    // ---------------------

    var Container = function (initialViews) {
        this._views = {};
        this._indexByModel = {};
        this._indexByCollection = {};
        this._indexByCustom = {};
        this._updateLength();

        this._addInitialViews(initialViews);
    };

    // Container Methods
    // -----------------

    _.extend(Container.prototype, {

        // Add a view to this container. Stores the view
        // by `cid` and makes it searchable by the model
        // and/or collection of the view. Optionally specify
        // a custom key to store an retrieve the view.
        add: function (view, customIndex) {
            var viewCid = view.cid;

            // store the view
            this._views[viewCid] = view;

            // index it by model
            if (view.model) {
                this._indexByModel[view.model.cid] = viewCid;
            }

            // index it by collection
            if (view.collection) {
                this._indexByCollection[view.collection.cid] = viewCid;
            }

            // index by custom
            if (customIndex) {
                this._indexByCustom[customIndex] = viewCid;
            }

            this._updateLength();
        },

        // Find a view by the model that was attached to
        // it. Uses the model's `cid` to find it, and
        // retrieves the view by it's `cid` from the result
        findByModel: function (model) {
            var viewCid = this._indexByModel[model.cid];
            return this.findByCid(viewCid);
        },

        // Find a view by the collection that was attached to
        // it. Uses the collection's `cid` to find it, and
        // retrieves the view by it's `cid` from the result
        findByCollection: function (col) {
            var viewCid = this._indexByCollection[col.cid];
            return this.findByCid(viewCid);
        },

        // Find a view by a custom indexer.
        findByCustom: function (index) {
            var viewCid = this._indexByCustom[index];
            return this.findByCid(viewCid);
        },

        // Find by index. This is not guaranteed to be a
        // stable index.
        findByIndex: function (index) {
            return _.values(this._views)[index];
        },

        // retrieve a view by it's `cid` directly
        findByCid: function (cid) {
            return this._views[cid];
        },

        // Remove a view
        remove: function (view) {
            var viewCid = view.cid;

            // delete model index
            if (view.model) {
                delete this._indexByModel[view.model.cid];
            }

            // delete collection index
            if (view.collection) {
                delete this._indexByCollection[view.collection.cid];
            }

            // delete custom index
            var cust;

            for (var key in this._indexByCustom) {
                if (this._indexByCustom.hasOwnProperty(key)) {
                    if (this._indexByCustom[key] === viewCid) {
                        cust = key;
                        break;
                    }
                }
            }

            if (cust) {
                delete this._indexByCustom[cust];
            }

            // remove the view from the container
            delete this._views[viewCid];

            // update the length
            this._updateLength();
        },

        // Call a method on every view in the container,
        // passing parameters to the call method one at a
        // time, like `function.call`.
        call: function (method, args) {
            args = Array.prototype.slice.call(arguments, 1);
            this.apply(method, args);
        },

        // Apply a method on every view in the container,
        // passing parameters to the call method one at a
        // time, like `function.apply`.
        apply: function (method, args) {
            var view;

            // fix for IE < 9
            args = args || [];

            _.each(this._views, function (view, key) {
                if (_.isFunction(view[method])) {
                    view[method].apply(view, args);
                }
            });

        },

        // Update the `.length` attribute on this container
        _updateLength: function () {
            this.length = _.size(this._views);
        },

        // set up an initial list of views
        _addInitialViews: function (views) {
            if (!views) { return; }

            var view, i,
                length = views.length;

            for (i = 0; i < length; i++) {
                view = views[i];
                this.add(view);
            }
        }
    });

    // Borrowing this code from Backbone.Collection:
    // http://backbonejs.org/docs/backbone.html#section-106
    //
    // Mix in methods from Underscore, for iteration, and other
    // collection related features.
    var methods = ['forEach', 'each', 'map', 'find', 'detect', 'filter',
      'select', 'reject', 'every', 'all', 'some', 'any', 'include',
      'contains', 'invoke', 'toArray', 'first', 'initial', 'rest',
      'last', 'without', 'isEmpty', 'pluck'];

    _.each(methods, function (method) {
        Container.prototype[method] = function () {
            var views = _.values(this._views);
            var args = [views].concat(_.toArray(arguments));
            return _[method].apply(_, args);
        };
    });

    // return the public API
    return Container;
})(Backbone, _);

// Backbone.Wreqr, v0.1.1
// Copyright (c)2013 Derick Bailey, Muted Solutions, LLC.
// Distributed under MIT license
// http://github.com/marionettejs/backbone.wreqr
Backbone.Wreqr = (function (Backbone, Marionette, _) {
    "use strict";
    var Wreqr = {};

    // Handlers
    // --------
    // A registry of functions to call, given a name

    Wreqr.Handlers = (function (Backbone, _) {
        "use strict";

        // Constructor
        // -----------

        var Handlers = function () {
            this._handlers = {};
        };

        Handlers.extend = Backbone.Model.extend;

        // Instance Members
        // ----------------

        _.extend(Handlers.prototype, {

            // Add a handler for the given name, with an
            // optional context to run the handler within
            addHandler: function (name, handler, context) {
                var config = {
                    callback: handler,
                    context: context
                };

                this._handlers[name] = config;
            },

            // Get the currently registered handler for
            // the specified name. Throws an exception if
            // no handler is found.
            getHandler: function (name) {
                var config = this._handlers[name];

                if (!config) {
                    throw new Error("Handler not found for '" + name + "'");
                }

                return function () {
                    var args = Array.prototype.slice.apply(arguments);
                    return config.callback.apply(config.context, args);
                };
            },

            // Remove a handler for the specified name
            removeHandler: function (name) {
                delete this._handlers[name];
            },

            // Remove all handlers from this registry
            removeAllHandlers: function () {
                this._handlers = {};
            }
        });

        return Handlers;
    })(Backbone, _);

    // Wreqr.Commands
    // --------------
    //
    // A simple command pattern implementation. Register a command
    // handler and execute it.
    Wreqr.Commands = (function (Wreqr) {
        "use strict";

        return Wreqr.Handlers.extend({
            execute: function () {
                var name = arguments[0];
                var args = Array.prototype.slice.call(arguments, 1);

                this.getHandler(name).apply(this, args);
            }
        });

    })(Wreqr);

    // Wreqr.RequestResponse
    // ---------------------
    //
    // A simple request/response implementation. Register a
    // request handler, and return a response from it
    Wreqr.RequestResponse = (function (Wreqr) {
        "use strict";

        return Wreqr.Handlers.extend({
            request: function () {
                var name = arguments[0];
                var args = Array.prototype.slice.call(arguments, 1);

                return this.getHandler(name).apply(this, args);
            }
        });

    })(Wreqr);

    // Event Aggregator
    // ----------------
    // A pub-sub object that can be used to decouple various parts
    // of an application through event-driven architecture.

    Wreqr.EventAggregator = (function (Backbone, _) {
        "use strict";
        var EA = function () { };

        // Copy the `extend` function used by Backbone's classes
        EA.extend = Backbone.Model.extend;

        // Copy the basic Backbone.Events on to the event aggregator
        _.extend(EA.prototype, Backbone.Events);

        return EA;
    })(Backbone, _);


    return Wreqr;
})(Backbone, Backbone.Marionette, _);

var Marionette = (function (Backbone, _, $) {
    "use strict";

    var Marionette = {};
    Backbone.Marionette = Marionette;

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

    // For slicing `arguments` in functions
    var slice = Array.prototype.slice;

    // Marionette.extend
    // -----------------

    // Borrow the Backbone `extend` method so we can use it as needed
    Marionette.extend = Backbone.Model.extend;

    // Marionette.getOption
    // --------------------

    // Retrieve an object, function or other value from a target
    // object or it's `options`, with `options` taking precedence.
    Marionette.getOption = function (target, optionName) {
        if (!target || !optionName) { return; }
        var value;

        if (target.options && (optionName in target.options) && (target.options[optionName] !== undefined)) {
            value = target.options[optionName];
        } else {
            value = target[optionName];
        }

        return value;
    };

    // Mairionette.createObject
    // ------------------------

    // A wrapper / shim for `Object.create`. Uses native `Object.create`
    // if available, otherwise shims it in place for Marionette to use.
    Marionette.createObject = (function () {
        var createObject;

        // Define this once, and just replace the .prototype on it as needed,
        // to improve performance in older / less optimized JS engines
        function F() { }


        // Check for existing native / shimmed Object.create
        if (typeof Object.create === "function") {

            // found native/shim, so use it
            createObject = Object.create;

        } else {

            // An implementation of the Boodman/Crockford delegation 
            // w/ Cornford optimization, as suggested by @unscriptable
            // https://gist.github.com/3959151

            // native/shim not found, so shim it ourself
            createObject = function (o) {

                // set the prototype of the function
                // so we will get `o` as the prototype
                // of the new object instance
                F.prototype = o;

                // create a new object that inherits from
                // the `o` parameter
                var child = new F();

                // clean up just in case o is really large
                F.prototype = null;

                // send it back
                return child;
            };

        }

        return createObject;
    })();

    // Trigger an event and a corresponding method name. Examples:
    //
    // `this.triggerMethod("foo")` will trigger the "foo" event and
    // call the "onFoo" method. 
    //
    // `this.triggerMethod("foo:bar") will trigger the "foo:bar" event and
    // call the "onFooBar" method.
    Marionette.triggerMethod = function () {
        var args = Array.prototype.slice.apply(arguments);
        var eventName = args[0];
        var segments = eventName.split(":");
        var segment, capLetter, methodName = "on";

        for (var i = 0; i < segments.length; i++) {
            segment = segments[i];
            capLetter = segment.charAt(0).toUpperCase();
            methodName += capLetter + segment.slice(1);
        }

        this.trigger.apply(this, args);

        if (_.isFunction(this[methodName])) {
            args.shift();
            return this[methodName].apply(this, args);
        }
    };

    // DOMRefresh
    // ----------
    //
    // Monitor a view's state, and after it has been rendered and shown
    // in the DOM, trigger a "dom:refresh" event every time it is
    // re-rendered.

    Marionette.MonitorDOMRefresh = (function () {
        // track when the view has been rendered
        function handleShow(view) {
            view._isShown = true;
            triggerDOMRefresh(view);
        }

        // track when the view has been shown in the DOM,
        // using a Marionette.Region (or by other means of triggering "show")
        function handleRender(view) {
            view._isRendered = true;
            triggerDOMRefresh(view);
        }

        // Trigger the "dom:refresh" event and corresponding "onDomRefresh" method
        function triggerDOMRefresh(view) {
            if (view._isShown && view._isRendered) {
                if (_.isFunction(view.triggerMethod)) {
                    view.triggerMethod("dom:refresh");
                }
            }
        }

        // Export public API
        return function (view) {
            view.listenTo(view, "show", function () {
                handleShow(view);
            });

            view.listenTo(view, "render", function () {
                handleRender(view);
            });
        };
    })();


    // Marionette.bindEntityEvents & unbindEntityEvents
    // ---------------------------
    //
    // These methods are used to bind/unbind a backbone "entity" (collection/model) 
    // to methods on a target object. 
    //
    // The first paremter, `target`, must have a `listenTo` method from the
    // EventBinder object.
    //
    // The second parameter is the entity (Backbone.Model or Backbone.Collection)
    // to bind the events from.
    //
    // The third parameter is a hash of { "event:name": "eventHandler" }
    // configuration. Multiple handlers can be separated by a space. A
    // function can be supplied instead of a string handler name. 

    (function (Marionette) {
        "use strict";

        // Bind the event to handlers specified as a string of
        // handler names on the target object
        function bindFromStrings(target, entity, evt, methods) {
            var methodNames = methods.split(/\s+/);

            _.each(methodNames, function (methodName) {

                var method = target[methodName];
                if (!method) {
                    throw new Error("Method '" + methodName + "' was configured as an event handler, but does not exist.");
                }

                target.listenTo(entity, evt, method, target);
            });
        }

        // Bind the event to a supplied callback function
        function bindToFunction(target, entity, evt, method) {
            target.listenTo(entity, evt, method, target);
        }

        // Bind the event to handlers specified as a string of
        // handler names on the target object
        function unbindFromStrings(target, entity, evt, methods) {
            var methodNames = methods.split(/\s+/);

            _.each(methodNames, function (methodName) {
                var method = target[method];
                target.stopListening(entity, evt, method, target);
            });
        }

        // Bind the event to a supplied callback function
        function unbindToFunction(target, entity, evt, method) {
            target.stopListening(entity, evt, method, target);
        }


        // generic looping function
        function iterateEvents(target, entity, bindings, functionCallback, stringCallback) {
            if (!entity || !bindings) { return; }

            // allow the bindings to be a function
            if (_.isFunction(bindings)) {
                bindings = bindings.call(target);
            }

            // iterate the bindings and bind them
            _.each(bindings, function (methods, evt) {

                // allow for a function as the handler, 
                // or a list of event names as a string
                if (_.isFunction(methods)) {
                    functionCallback(target, entity, evt, methods);
                } else {
                    stringCallback(target, entity, evt, methods);
                }

            });
        }

        // Export Public API
        Marionette.bindEntityEvents = function (target, entity, bindings) {
            iterateEvents(target, entity, bindings, bindToFunction, bindFromStrings);
        };

        Marionette.unbindEntityEvents = function (target, entity, bindings) {
            iterateEvents(target, entity, bindings, unbindToFunction, unbindFromStrings);
        };

    })(Marionette);


    // Callbacks
    // ---------

    // A simple way of managing a collection of callbacks
    // and executing them at a later point in time, using jQuery's
    // `Deferred` object.
    Marionette.Callbacks = function () {
        this._deferred = $.Deferred();
        this._callbacks = [];
    };

    _.extend(Marionette.Callbacks.prototype, {

        // Add a callback to be executed. Callbacks added here are
        // guaranteed to execute, even if they are added after the 
        // `run` method is called.
        add: function (callback, contextOverride) {
            this._callbacks.push({ cb: callback, ctx: contextOverride });

            this._deferred.done(function (context, options) {
                if (contextOverride) { context = contextOverride; }
                callback.call(context, options);
            });
        },

        // Run all registered callbacks with the context specified. 
        // Additional callbacks can be added after this has been run 
        // and they will still be executed.
        run: function (options, context) {
            this._deferred.resolve(context, options);
        },

        // Resets the list of callbacks to be run, allowing the same list
        // to be run multiple times - whenever the `run` method is called.
        reset: function () {
            var that = this;
            var callbacks = this._callbacks;
            this._deferred = $.Deferred();
            this._callbacks = [];
            _.each(callbacks, function (cb) {
                that.add(cb.cb, cb.ctx);
            });
        }
    });


    // Marionette Controller
    // ---------------------
    //
    // A multi-purpose object to use as a controller for
    // modules and routers, and as a mediator for workflow
    // and coordination of other objects, views, and more.
    Marionette.Controller = function (options) {
        this.triggerMethod = Marionette.triggerMethod;
        this.options = options || {};

        if (_.isFunction(this.initialize)) {
            this.initialize(this.options);
        }
    };

    Marionette.Controller.extend = Marionette.extend;

    // Controller Methods
    // --------------

    // Ensure it can trigger events with Backbone.Events
    _.extend(Marionette.Controller.prototype, Backbone.Events, {
        close: function () {
            this.stopListening();
            this.triggerMethod("close");
            this.unbind();
        }
    });

    // Region 
    // ------
    //
    // Manage the visual regions of your composite application. See
    // http://lostechies.com/derickbailey/2011/12/12/composite-js-apps-regions-and-region-managers/

    Marionette.Region = function (options) {
        this.options = options || {};

        this.el = Marionette.getOption(this, "el");

        if (!this.el) {
            var err = new Error("An 'el' must be specified for a region.");
            err.name = "NoElError";
            throw err;
        }

        if (this.initialize) {
            var args = Array.prototype.slice.apply(arguments);
            this.initialize.apply(this, args);
        }
    };


    // Region Type methods
    // -------------------

    _.extend(Marionette.Region, {

        // Build an instance of a region by passing in a configuration object
        // and a default region type to use if none is specified in the config.
        //
        // The config object should either be a string as a jQuery DOM selector,
        // a Region type directly, or an object literal that specifies both
        // a selector and regionType:
        //
        // ```js
        // {
        //   selector: "#foo",
        //   regionType: MyCustomRegion
        // }
        // ```
        //
        buildRegion: function (regionConfig, defaultRegionType) {
            var regionIsString = (typeof regionConfig === "string");
            var regionSelectorIsString = (typeof regionConfig.selector === "string");
            var regionTypeIsUndefined = (typeof regionConfig.regionType === "undefined");
            var regionIsType = (typeof regionConfig === "function");

            if (!regionIsType && !regionIsString && !regionSelectorIsString) {
                throw new Error("Region must be specified as a Region type, a selector string or an object with selector property");
            }

            var selector, RegionType;

            // get the selector for the region

            if (regionIsString) {
                selector = regionConfig;
            }

            if (regionConfig.selector) {
                selector = regionConfig.selector;
            }

            // get the type for the region

            if (regionIsType) {
                RegionType = regionConfig;
            }

            if (!regionIsType && regionTypeIsUndefined) {
                RegionType = defaultRegionType;
            }

            if (regionConfig.regionType) {
                RegionType = regionConfig.regionType;
            }

            // build the region instance

            var regionManager = new RegionType({
                el: selector
            });

            return regionManager;
        }

    });

    // Region Instance Methods
    // -----------------------

    _.extend(Marionette.Region.prototype, Backbone.Events, {

        // Displays a backbone view instance inside of the region.
        // Handles calling the `render` method for you. Reads content
        // directly from the `el` attribute. Also calls an optional
        // `onShow` and `close` method on your view, just after showing
        // or just before closing the view, respectively.
        show: function (view) {

            this.ensureEl();
            this.close();

            view.render();
            this.open(view);

            Marionette.triggerMethod.call(view, "show");
            Marionette.triggerMethod.call(this, "show", view);

            this.currentView = view;
        },

        ensureEl: function () {
            if (!this.$el || this.$el.length === 0) {
                this.$el = this.getEl(this.el);
            }
        },

        // Override this method to change how the region finds the
        // DOM element that it manages. Return a jQuery selector object.
        getEl: function (selector) {
            return $(selector);
        },

        // Override this method to change how the new view is
        // appended to the `$el` that the region is managing
        open: function (view) {
            this.$el.empty().append(view.el);
        },

        // Close the current view, if there is one. If there is no
        // current view, it does nothing and returns immediately.
        close: function () {
            var view = this.currentView;
            if (!view || view.isClosed) { return; }

            if (view.close) { view.close(); }
            Marionette.triggerMethod.call(this, "close");

            delete this.currentView;
        },

        // Attach an existing view to the region. This 
        // will not call `render` or `onShow` for the new view, 
        // and will not replace the current HTML for the `el`
        // of the region.
        attachView: function (view) {
            this.currentView = view;
        },

        // Reset the region by closing any existing view and
        // clearing out the cached `$el`. The next time a view
        // is shown via this region, the region will re-query the
        // DOM for the region's `el`.
        reset: function () {
            this.close();
            delete this.$el;
        }
    });

    // Copy the `extend` function used by Backbone's classes
    Marionette.Region.extend = Marionette.extend;


    // Template Cache
    // --------------

    // Manage templates stored in `<script>` blocks,
    // caching them for faster access.
    Marionette.TemplateCache = function (templateId) {
        this.templateId = templateId;
    };

    // TemplateCache object-level methods. Manage the template
    // caches from these method calls instead of creating 
    // your own TemplateCache instances
    _.extend(Marionette.TemplateCache, {
        templateCaches: {},

        // Get the specified template by id. Either
        // retrieves the cached version, or loads it
        // from the DOM.
        get: function (templateId) {
            var that = this;
            var cachedTemplate = this.templateCaches[templateId];

            if (!cachedTemplate) {
                cachedTemplate = new Marionette.TemplateCache(templateId);
                this.templateCaches[templateId] = cachedTemplate;
            }

            return cachedTemplate.load();
        },

        // Clear templates from the cache. If no arguments
        // are specified, clears all templates:
        // `clear()`
        //
        // If arguments are specified, clears each of the 
        // specified templates from the cache:
        // `clear("#t1", "#t2", "...")`
        clear: function () {
            var i;
            var args = Array.prototype.slice.apply(arguments);
            var length = args.length;

            if (length > 0) {
                for (i = 0; i < length; i++) {
                    delete this.templateCaches[args[i]];
                }
            } else {
                this.templateCaches = {};
            }
        }
    });

    // TemplateCache instance methods, allowing each
    // template cache object to manage it's own state
    // and know whether or not it has been loaded
    _.extend(Marionette.TemplateCache.prototype, {

        // Internal method to load the template
        load: function () {
            var that = this;

            // Guard clause to prevent loading this template more than once
            if (this.compiledTemplate) {
                return this.compiledTemplate;
            }

            // Load the template and compile it
            var template = this.loadTemplate(this.templateId);
            this.compiledTemplate = this.compileTemplate(template);

            return this.compiledTemplate;
        },

        // Load a template from the DOM, by default. Override
        // this method to provide your own template retrieval
        // For asynchronous loading with AMD/RequireJS, consider
        // using a template-loader plugin as described here: 
        // https://github.com/marionettejs/backbone.marionette/wiki/Using-marionette-with-requirejs
        loadTemplate: function (templateId) {
            var template = $(templateId).html();

            if (!template || template.length === 0) {
                var msg = "Could not find template: '" + templateId + "'";
                var err = new Error(msg);
                err.name = "NoTemplateError";
                throw err;
            }

            return template;
        },

        // Pre-compile the template before caching it. Override
        // this method if you do not need to pre-compile a template
        // (JST / RequireJS for example) or if you want to change
        // the template engine used (Handebars, etc).
        compileTemplate: function (rawTemplate) {
            return _.template(rawTemplate);
        }
    });


    // Renderer
    // --------

    // Render a template with data by passing in the template
    // selector and the data to render.
    Marionette.Renderer = {

        // Render a template with data. The `template` parameter is
        // passed to the `TemplateCache` object to retrieve the
        // template function. Override this method to provide your own
        // custom rendering and template handling for all of Marionette.
        render: function (template, data) {
            var templateFunc = typeof template === 'function' ? template : Marionette.TemplateCache.get(template);
            var html = templateFunc(data);
            return html;
        }
    };



    // Marionette.View
    // ---------------

    // The core view type that other Marionette views extend from.
    Marionette.View = Backbone.View.extend({

        constructor: function () {
            _.bindAll(this, "render");

            var args = Array.prototype.slice.apply(arguments);
            Backbone.View.prototype.constructor.apply(this, args);

            Marionette.MonitorDOMRefresh(this);
            this.listenTo(this, "show", this.onShowCalled, this);
        },

        // import the "triggerMethod" to trigger events with corresponding
        // methods if the method exists 
        triggerMethod: Marionette.triggerMethod,

        // Get the template for this view
        // instance. You can set a `template` attribute in the view
        // definition or pass a `template: "whatever"` parameter in
        // to the constructor options.
        getTemplate: function () {
            return Marionette.getOption(this, "template");
        },

        // Mix in template helper methods. Looks for a
        // `templateHelpers` attribute, which can either be an
        // object literal, or a function that returns an object
        // literal. All methods and attributes from this object
        // are copies to the object passed in.
        mixinTemplateHelpers: function (target) {
            target = target || {};
            var templateHelpers = this.templateHelpers;
            if (_.isFunction(templateHelpers)) {
                templateHelpers = templateHelpers.call(this);
            }
            return _.extend(target, templateHelpers);
        },

        // Configure `triggers` to forward DOM events to view
        // events. `triggers: {"click .foo": "do:foo"}`
        configureTriggers: function () {
            if (!this.triggers) { return; }

            var that = this;
            var triggerEvents = {};

            // Allow `triggers` to be configured as a function
            var triggers = _.result(this, "triggers");

            // Configure the triggers, prevent default
            // action and stop propagation of DOM events
            _.each(triggers, function (value, key) {

                // build the event handler function for the DOM event
                triggerEvents[key] = function (e) {

                    // stop the event in it's tracks
                    if (e && e.preventDefault) { e.preventDefault(); }
                    if (e && e.stopPropagation) { e.stopPropagation(); }

                    // buil the args for the event
                    var args = {
                        view: this,
                        model: this.model,
                        collection: this.collection
                    };

                    // trigger the event
                    that.triggerMethod(value, args);
                };

            });

            return triggerEvents;
        },

        // Overriding Backbone.View's delegateEvents to handle 
        // the `triggers`, `modelEvents`, and `collectionEvents` configuration
        delegateEvents: function (events) {
            this._delegateDOMEvents(events);
            Marionette.bindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
            Marionette.bindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
        },

        // internal method to delegate DOM events and triggers
        _delegateDOMEvents: function (events) {
            events = events || this.events;
            if (_.isFunction(events)) { events = events.call(this); }

            var combinedEvents = {};
            var triggers = this.configureTriggers();
            _.extend(combinedEvents, events, triggers);

            Backbone.View.prototype.delegateEvents.call(this, combinedEvents);
        },

        // Overriding Backbone.View's undelegateEvents to handle unbinding
        // the `triggers`, `modelEvents`, and `collectionEvents` config
        undelegateEvents: function () {
            var args = Array.prototype.slice.call(arguments);
            Backbone.View.prototype.undelegateEvents.apply(this, args);

            Marionette.unbindEntityEvents(this, this.model, Marionette.getOption(this, "modelEvents"));
            Marionette.unbindEntityEvents(this, this.collection, Marionette.getOption(this, "collectionEvents"));
        },

        // Internal method, handles the `show` event.
        onShowCalled: function () { },

        // Default `close` implementation, for removing a view from the
        // DOM and unbinding it. Regions will call this method
        // for you. You can specify an `onClose` method in your view to
        // add custom code that is called after the view is closed.
        close: function () {
            if (this.isClosed) { return; }

            // allow the close to be stopped by returning `false`
            // from the `onBeforeClose` method
            var shouldClose = this.triggerMethod("before:close");
            if (shouldClose === false) {
                return;
            }

            // mark as closed before doing the actual close, to
            // prevent infinite loops within "close" event handlers
            // that are trying to close other views
            this.isClosed = true;
            this.triggerMethod("close");

            this.remove();
        },

        // This method binds the elements specified in the "ui" hash inside the view's code with
        // the associated jQuery selectors.
        bindUIElements: function () {
            if (!this.ui) { return; }

            var that = this;

            if (!this.uiBindings) {
                // We want to store the ui hash in uiBindings, since afterwards the values in the ui hash
                // will be overridden with jQuery selectors.
                this.uiBindings = _.result(this, "ui");
            }

            // refreshing the associated selectors since they should point to the newly rendered elements.
            this.ui = {};
            _.each(_.keys(this.uiBindings), function (key) {
                var selector = that.uiBindings[key];
                that.ui[key] = that.$(selector);
            });
        }
    });

    // Item View
    // ---------

    // A single item view implementation that contains code for rendering
    // with underscore.js templates, serializing the view's model or collection,
    // and calling several methods on extended views, such as `onRender`.
    Marionette.ItemView = Marionette.View.extend({
        constructor: function () {
            var args = Array.prototype.slice.apply(arguments);
            Marionette.View.prototype.constructor.apply(this, args);
        },

        // Serialize the model or collection for the view. If a model is
        // found, `.toJSON()` is called. If a collection is found, `.toJSON()`
        // is also called, but is used to populate an `items` array in the
        // resulting data. If both are found, defaults to the model.
        // You can override the `serializeData` method in your own view
        // definition, to provide custom serialization for your view's data.
        serializeData: function () {
            var data = {};

            if (this.model) {
                data = this.model.toJSON();
            }
            else if (this.collection) {
                data = { items: this.collection.toJSON() };
            }

            return data;
        },

        // Render the view, defaulting to underscore.js templates.
        // You can override this in your view definition to provide
        // a very specific rendering for your view. In general, though,
        // you should override the `Marionette.Renderer` object to
        // change how Marionette renders views.
        render: function () {
            this.isClosed = false;

            this.triggerMethod("before:render", this);
            this.triggerMethod("item:before:render", this);

            var data = this.serializeData();
            data = this.mixinTemplateHelpers(data);

            var template = this.getTemplate();
            var html = Marionette.Renderer.render(template, data);
            this.$el.html(html);
            this.bindUIElements();

            this.triggerMethod("render", this);
            this.triggerMethod("item:rendered", this);

            return this;
        },

        // Override the default close event to add a few
        // more events that are triggered.
        close: function () {
            if (this.isClosed) { return; }

            this.triggerMethod('item:before:close');

            var args = Array.prototype.slice.apply(arguments);
            Marionette.View.prototype.close.apply(this, args);

            this.triggerMethod('item:closed');
        }
    });

    // Collection View
    // ---------------

    // A view that iterates over a Backbone.Collection
    // and renders an individual ItemView for each model.
    Marionette.CollectionView = Marionette.View.extend({
        // used as the prefix for item view events
        // that are forwarded through the collectionview
        itemViewEventPrefix: "itemview",

        // constructor
        constructor: function (options) {
            this._initChildViewStorage();

            var args = Array.prototype.slice.apply(arguments);
            Marionette.View.prototype.constructor.apply(this, args);

            this._initialEvents();
        },

        // Configured the initial events that the collection view
        // binds to. Override this method to prevent the initial
        // events, or to add your own initial events.
        _initialEvents: function () {
            if (this.collection) {
                this.listenTo(this.collection, "add", this.addChildView, this);
                this.listenTo(this.collection, "remove", this.removeItemView, this);
                this.listenTo(this.collection, "reset", this.render, this);
            }
        },

        // Handle a child item added to the collection
        addChildView: function (item, collection, options) {
            this.closeEmptyView();
            var ItemView = this.getItemView(item);
            var index = this.collection.indexOf(item);
            this.addItemView(item, ItemView, index);
        },

        // Override from `Marionette.View` to guarantee the `onShow` method
        // of child views is called.
        onShowCalled: function () {
            this.children.each(function (child) {
                Marionette.triggerMethod.call(child, "show");
            });
        },

        // Internal method to trigger the before render callbacks
        // and events
        triggerBeforeRender: function () {
            this.triggerMethod("before:render", this);
            this.triggerMethod("collection:before:render", this);
        },

        // Internal method to trigger the rendered callbacks and
        // events
        triggerRendered: function () {
            this.triggerMethod("render", this);
            this.triggerMethod("collection:rendered", this);
        },

        // Render the collection of items. Override this method to
        // provide your own implementation of a render function for
        // the collection view.
        render: function () {
            this.isClosed = false;

            this.triggerBeforeRender();
            this.closeEmptyView();
            this.closeChildren();

            if (this.collection && this.collection.length > 0) {
                this.showCollection();
            } else {
                this.showEmptyView();
            }

            this.triggerRendered();
            return this;
        },

        // Internal method to loop through each item in the
        // collection view and show it
        showCollection: function () {
            var that = this;
            var ItemView;
            this.collection.each(function (item, index) {
                ItemView = that.getItemView(item);
                that.addItemView(item, ItemView, index);
            });
        },

        // Internal method to show an empty view in place of
        // a collection of item views, when the collection is
        // empty
        showEmptyView: function () {
            var EmptyView = Marionette.getOption(this, "emptyView");

            if (EmptyView && !this._showingEmptyView) {
                this._showingEmptyView = true;
                var model = new Backbone.Model();
                this.addItemView(model, EmptyView, 0);
            }
        },

        // Internal method to close an existing emptyView instance
        // if one exists. Called when a collection view has been
        // rendered empty, and then an item is added to the collection.
        closeEmptyView: function () {
            if (this._showingEmptyView) {
                this.closeChildren();
                delete this._showingEmptyView;
            }
        },

        // Retrieve the itemView type, either from `this.options.itemView`
        // or from the `itemView` in the object definition. The "options"
        // takes precedence.
        getItemView: function (item) {
            var itemView = Marionette.getOption(this, "itemView");

            if (!itemView) {
                var err = new Error("An `itemView` must be specified");
                err.name = "NoItemViewError";
                throw err;
            }

            return itemView;
        },

        // Render the child item's view and add it to the
        // HTML for the collection view.
        addItemView: function (item, ItemView, index) {
            var that = this;

            // get the itemViewOptions if any were specified
            var itemViewOptions = Marionette.getOption(this, "itemViewOptions");
            if (_.isFunction(itemViewOptions)) {
                itemViewOptions = itemViewOptions.call(this, item);
            }

            // build the view 
            var view = this.buildItemView(item, ItemView, itemViewOptions);

            // set up the child view event forwarding
            this.addChildViewEventForwarding(view);

            // this view is about to be added
            this.triggerMethod("before:item:added", view);

            // Store the child view itself so we can properly
            // remove and/or close it later
            this.children.add(view);

            // Render it and show it
            this.renderItemView(view, index);

            // call the "show" method if the collection view
            // has already been shown
            if (this._isShown) {
                Marionette.triggerMethod.call(view, "show");
            }

            // this view was added
            this.triggerMethod("after:item:added", view);
        },

        // Set up the child view event forwarding. Uses an "itemview:"
        // prefix in front of all forwarded events.
        addChildViewEventForwarding: function (view) {
            var prefix = Marionette.getOption(this, "itemViewEventPrefix");

            // Forward all child item view events through the parent,
            // prepending "itemview:" to the event name
            this.listenTo(view, "all", function () {
                var args = slice.call(arguments);
                args[0] = prefix + ":" + args[0];
                args.splice(1, 0, view);

                Marionette.triggerMethod.apply(this, args);
            }, this);
        },

        // render the item view
        renderItemView: function (view, index) {
            view.render();
            this.appendHtml(this, view, index);
        },

        // Build an `itemView` for every model in the collection.
        buildItemView: function (item, ItemViewType, itemViewOptions) {
            var options = _.extend({ model: item }, itemViewOptions);
            var view = new ItemViewType(options);
            return view;
        },

        // get the child view by item it holds, and remove it
        removeItemView: function (item) {
            var view = this.children.findByModel(item);
            this.removeChildView(view);
            this.checkEmpty();
        },

        // Remove the child view and close it
        removeChildView: function (view) {

            // shut down the child view properly,
            // including events that the collection has from it
            if (view) {
                this.stopListening(view);

                if (view.close) {
                    view.close();
                }

                this.children.remove(view);
            }

            this.triggerMethod("item:removed", view);
        },

        // helper to show the empty view if the collection is empty
        checkEmpty: function () {
            // check if we're empty now, and if we are, show the
            // empty view
            if (!this.collection || this.collection.length === 0) {
                this.showEmptyView();
            }
        },

        // Append the HTML to the collection's `el`.
        // Override this method to do something other
        // then `.append`.
        appendHtml: function (collectionView, itemView, index) {
            collectionView.$el.append(itemView.el);
        },

        // Internal method to set up the `children` object for
        // storing all of the child views
        _initChildViewStorage: function () {
            this.children = new Backbone.ChildViewContainer();
        },

        // Handle cleanup and other closing needs for
        // the collection of views.
        close: function () {
            if (this.isClosed) { return; }

            this.triggerMethod("collection:before:close");
            this.closeChildren();
            this.triggerMethod("collection:closed");

            var args = Array.prototype.slice.apply(arguments);
            Marionette.View.prototype.close.apply(this, args);
        },

        // Close the child views that this collection view
        // is holding on to, if any
        closeChildren: function () {
            this.children.each(function (child) {
                this.removeChildView(child);
            }, this);
            this.checkEmpty();
        }
    });


    // Composite View
    // --------------

    // Used for rendering a branch-leaf, hierarchical structure.
    // Extends directly from CollectionView and also renders an
    // an item view as `modelView`, for the top leaf
    Marionette.CompositeView = Marionette.CollectionView.extend({
        constructor: function (options) {
            var args = Array.prototype.slice.apply(arguments);
            Marionette.CollectionView.apply(this, args);

            this.itemView = this.getItemView();
        },

        // Configured the initial events that the composite view
        // binds to. Override this method to prevent the initial
        // events, or to add your own initial events.
        _initialEvents: function () {
            if (this.collection) {
                this.listenTo(this.collection, "add", this.addChildView, this);
                this.listenTo(this.collection, "remove", this.removeItemView, this);
                this.listenTo(this.collection, "reset", this.renderCollection, this);
            }
        },

        // Retrieve the `itemView` to be used when rendering each of
        // the items in the collection. The default is to return
        // `this.itemView` or Marionette.CompositeView if no `itemView`
        // has been defined
        getItemView: function (item) {
            var itemView = Marionette.getOption(this, "itemView") || this.constructor;

            if (!itemView) {
                var err = new Error("An `itemView` must be specified");
                err.name = "NoItemViewError";
                throw err;
            }

            return itemView;
        },

        // Serialize the collection for the view. 
        // You can override the `serializeData` method in your own view
        // definition, to provide custom serialization for your view's data.
        serializeData: function () {
            var data = {};

            if (this.model) {
                data = this.model.toJSON();
            }

            return data;
        },

        // Renders the model once, and the collection once. Calling
        // this again will tell the model's view to re-render itself
        // but the collection will not re-render.
        render: function () {
            this.isClosed = false;

            this.resetItemViewContainer();

            var html = this.renderModel();
            this.$el.html(html);

            // the ui bindings is done here and not at the end of render since they 
            // will not be available until after the model is rendered, but should be
            // available before the collection is rendered.
            this.bindUIElements();

            this.triggerMethod("composite:model:rendered");

            this.renderCollection();
            this.triggerMethod("composite:rendered");
            return this;
        },

        // Render the collection for the composite view
        renderCollection: function () {
            var args = Array.prototype.slice.apply(arguments);
            Marionette.CollectionView.prototype.render.apply(this, args);

            this.triggerMethod("composite:collection:rendered");
        },

        // Render an individual model, if we have one, as
        // part of a composite view (branch / leaf). For example:
        // a treeview.
        renderModel: function () {
            var data = {};
            data = this.serializeData();
            data = this.mixinTemplateHelpers(data);

            var template = this.getTemplate();
            return Marionette.Renderer.render(template, data);
        },

        // Appends the `el` of itemView instances to the specified
        // `itemViewContainer` (a jQuery selector). Override this method to
        // provide custom logic of how the child item view instances have their
        // HTML appended to the composite view instance.
        appendHtml: function (cv, iv) {
            var $container = this.getItemViewContainer(cv);
            $container.append(iv.el);
        },

        // Internal method to ensure an `$itemViewContainer` exists, for the
        // `appendHtml` method to use.
        getItemViewContainer: function (containerView) {
            if ("$itemViewContainer" in containerView) {
                return containerView.$itemViewContainer;
            }

            var container;
            if (containerView.itemViewContainer) {

                var selector = _.result(containerView, "itemViewContainer");
                container = containerView.$(selector);
                if (container.length <= 0) {
                    var err = new Error("The specified `itemViewContainer` was not found: " + containerView.itemViewContainer);
                    err.name = "ItemViewContainerMissingError";
                    throw err;
                }

            } else {
                container = containerView.$el;
            }

            containerView.$itemViewContainer = container;
            return container;
        },

        // Internal method to reset the `$itemViewContainer` on render
        resetItemViewContainer: function () {
            if (this.$itemViewContainer) {
                delete this.$itemViewContainer;
            }
        }
    });


    // Layout
    // ------

    // Used for managing application layouts, nested layouts and
    // multiple regions within an application or sub-application.
    //
    // A specialized view type that renders an area of HTML and then
    // attaches `Region` instances to the specified `regions`.
    // Used for composite view management and sub-application areas.
    Marionette.Layout = Marionette.ItemView.extend({
        regionType: Marionette.Region,

        // Ensure the regions are avialable when the `initialize` method
        // is called.
        constructor: function () {
            this._firstRender = true;
            this.initializeRegions();

            var args = Array.prototype.slice.apply(arguments);
            Marionette.ItemView.apply(this, args);
        },

        // Layout's render will use the existing region objects the
        // first time it is called. Subsequent calls will close the
        // views that the regions are showing and then reset the `el`
        // for the regions to the newly rendered DOM elements.
        render: function () {

            if (this._firstRender) {
                // if this is the first render, don't do anything to
                // reset the regions
                this._firstRender = false;
            } else {
                // If this is not the first render call, then we need to 
                // re-initializing the `el` for each region
                this.closeRegions();
                this.reInitializeRegions();
            }

            var args = Array.prototype.slice.apply(arguments);
            var result = Marionette.ItemView.prototype.render.apply(this, args);

            return result;
        },

        // Handle closing regions, and then close the view itself.
        close: function () {
            if (this.isClosed) { return; }

            this.closeRegions();
            this.destroyRegions();

            var args = Array.prototype.slice.apply(arguments);
            Marionette.ItemView.prototype.close.apply(this, args);
        },

        // Initialize the regions that have been defined in a
        // `regions` attribute on this layout. The key of the
        // hash becomes an attribute on the layout object directly.
        // For example: `regions: { menu: ".menu-container" }`
        // will product a `layout.menu` object which is a region
        // that controls the `.menu-container` DOM element.
        initializeRegions: function () {
            if (!this.regionManagers) {
                this.regionManagers = {};
            }

            var that = this;
            var regions = this.regions || {};
            _.each(regions, function (region, name) {

                var regionManager = Marionette.Region.buildRegion(region, that.regionType);
                regionManager.getEl = function (selector) {
                    return that.$(selector);
                };

                that.regionManagers[name] = regionManager;
                that[name] = regionManager;
            });

        },

        // Re-initialize all of the regions by updating the `el` that
        // they point to
        reInitializeRegions: function () {
            if (this.regionManagers && _.size(this.regionManagers) === 0) {
                this.initializeRegions();
            } else {
                _.each(this.regionManagers, function (region) {
                    region.reset();
                });
            }
        },

        // Close all of the regions that have been opened by
        // this layout. This method is called when the layout
        // itself is closed.
        closeRegions: function () {
            var that = this;
            _.each(this.regionManagers, function (manager, name) {
                manager.close();
            });
        },

        // Destroys all of the regions by removing references
        // from the Layout
        destroyRegions: function () {
            var that = this;
            _.each(this.regionManagers, function (manager, name) {
                delete that[name];
            });
            this.regionManagers = {};
        }
    });



    // AppRouter
    // ---------

    // Reduce the boilerplate code of handling route events
    // and then calling a single method on another object.
    // Have your routers configured to call the method on
    // your object, directly.
    //
    // Configure an AppRouter with `appRoutes`.
    //
    // App routers can only take one `controller` object. 
    // It is recommended that you divide your controller
    // objects in to smaller peices of related functionality
    // and have multiple routers / controllers, instead of
    // just one giant router and controller.
    //
    // You can also add standard routes to an AppRouter.

    Marionette.AppRouter = Backbone.Router.extend({

        constructor: function (options) {
            var args = Array.prototype.slice.apply(arguments);
            Backbone.Router.prototype.constructor.apply(this, args);

            this.options = options;

            if (this.appRoutes) {
                var controller = Marionette.getOption(this, "controller");
                this.processAppRoutes(controller, this.appRoutes);
            }
        },

        // Internal method to process the `appRoutes` for the
        // router, and turn them in to routes that trigger the
        // specified method on the specified `controller`.
        processAppRoutes: function (controller, appRoutes) {
            var method, methodName;
            var route, routesLength, i;
            var routes = [];
            var router = this;

            for (route in appRoutes) {
                if (appRoutes.hasOwnProperty(route)) {
                    routes.unshift([route, appRoutes[route]]);
                }
            }

            routesLength = routes.length;
            for (i = 0; i < routesLength; i++) {
                route = routes[i][0];
                methodName = routes[i][1];
                method = controller[methodName];

                if (!method) {
                    var msg = "Method '" + methodName + "' was not found on the controller";
                    var err = new Error(msg);
                    err.name = "NoMethodError";
                    throw err;
                }

                method = _.bind(method, controller);
                router.route(route, methodName, method);
            }
        }
    });


    // Application
    // -----------

    // Contain and manage the composite application as a whole.
    // Stores and starts up `Region` objects, includes an
    // event aggregator as `app.vent`
    Marionette.Application = function (options) {
        this.initCallbacks = new Marionette.Callbacks();
        this.vent = new Backbone.Wreqr.EventAggregator();
        this.commands = new Backbone.Wreqr.Commands();
        this.reqres = new Backbone.Wreqr.RequestResponse();
        this.submodules = {};

        _.extend(this, options);

        this.triggerMethod = Marionette.triggerMethod;
    };

    _.extend(Marionette.Application.prototype, Backbone.Events, {
        // Command execution, facilitated by Backbone.Wreqr.Commands
        execute: function () {
            var args = Array.prototype.slice.apply(arguments);
            this.commands.execute.apply(this.commands, args);
        },

        // Request/response, facilitated by Backbone.Wreqr.RequestResponse
        request: function () {
            var args = Array.prototype.slice.apply(arguments);
            return this.reqres.request.apply(this.reqres, args);
        },

        // Add an initializer that is either run at when the `start`
        // method is called, or run immediately if added after `start`
        // has already been called.
        addInitializer: function (initializer) {
            this.initCallbacks.add(initializer);
        },

        // kick off all of the application's processes.
        // initializes all of the regions that have been added
        // to the app, and runs all of the initializer functions
        start: function (options) {
            this.triggerMethod("initialize:before", options);
            this.initCallbacks.run(options, this);
            this.triggerMethod("initialize:after", options);

            this.triggerMethod("start", options);
        },

        // Add regions to your app. 
        // Accepts a hash of named strings or Region objects
        // addRegions({something: "#someRegion"})
        // addRegions{{something: Region.extend({el: "#someRegion"}) });
        addRegions: function (regions) {
            var that = this;
            _.each(regions, function (region, name) {
                var regionManager = Marionette.Region.buildRegion(region, Marionette.Region);
                that[name] = regionManager;
            });
        },

        // Removes a region from your app.
        // Accepts the regions name
        // removeRegion('myRegion')
        removeRegion: function (region) {
            this[region].close();
            delete this[region];
        },

        // Create a module, attached to the application
        module: function (moduleNames, moduleDefinition) {
            // slice the args, and add this application object as the
            // first argument of the array
            var args = slice.call(arguments);
            args.unshift(this);

            // see the Marionette.Module object for more information
            return Marionette.Module.create.apply(Marionette.Module, args);
        }
    });

    // Copy the `extend` function used by Backbone's classes
    Marionette.Application.extend = Marionette.extend;

    // Module
    // ------

    // A simple module system, used to create privacy and encapsulation in
    // Marionette applications
    Marionette.Module = function (moduleName, app) {
        this.moduleName = moduleName;

        // store sub-modules
        this.submodules = {};

        this._setupInitializersAndFinalizers();

        // store the configuration for this module
        this.app = app;
        this.startWithParent = true;

        this.triggerMethod = Marionette.triggerMethod;
    };

    // Extend the Module prototype with events / listenTo, so that the module
    // can be used as an event aggregator or pub/sub.
    _.extend(Marionette.Module.prototype, Backbone.Events, {

        // Initializer for a specific module. Initializers are run when the
        // module's `start` method is called.
        addInitializer: function (callback) {
            this._initializerCallbacks.add(callback);
        },

        // Finalizers are run when a module is stopped. They are used to teardown
        // and finalize any variables, references, events and other code that the
        // module had set up.
        addFinalizer: function (callback) {
            this._finalizerCallbacks.add(callback);
        },

        // Start the module, and run all of it's initializers
        start: function (options) {
            // Prevent re-starting a module that is already started
            if (this._isInitialized) { return; }

            // start the sub-modules (depth-first hierarchy)
            _.each(this.submodules, function (mod) {
                // check to see if we should start the sub-module with this parent
                var startWithParent = true;
                startWithParent = mod.startWithParent;

                // start the sub-module
                if (startWithParent) {
                    mod.start(options);
                }
            });

            // run the callbacks to "start" the current module
            this.triggerMethod("before:start", options);

            this._initializerCallbacks.run(options, this);
            this._isInitialized = true;

            this.triggerMethod("start", options);
        },

        // Stop this module by running its finalizers and then stop all of
        // the sub-modules for this module
        stop: function () {
            // if we are not initialized, don't bother finalizing
            if (!this._isInitialized) { return; }
            this._isInitialized = false;

            Marionette.triggerMethod.call(this, "before:stop");

            // stop the sub-modules; depth-first, to make sure the
            // sub-modules are stopped / finalized before parents
            _.each(this.submodules, function (mod) { mod.stop(); });

            // run the finalizers
            this._finalizerCallbacks.run(undefined, this);

            // reset the initializers and finalizers
            this._initializerCallbacks.reset();
            this._finalizerCallbacks.reset();

            Marionette.triggerMethod.call(this, "stop");
        },

        // Configure the module with a definition function and any custom args
        // that are to be passed in to the definition function
        addDefinition: function (moduleDefinition, customArgs) {
            this._runModuleDefinition(moduleDefinition, customArgs);
        },

        // Internal method: run the module definition function with the correct
        // arguments
        _runModuleDefinition: function (definition, customArgs) {
            if (!definition) { return; }

            // build the correct list of arguments for the module definition
            var args = _.flatten([
              this,
              this.app,
              Backbone,
              Marionette,
              $, _,
              customArgs
            ]);

            definition.apply(this, args);
        },

        // Internal method: set up new copies of initializers and finalizers.
        // Calling this method will wipe out all existing initializers and
        // finalizers.
        _setupInitializersAndFinalizers: function () {
            this._initializerCallbacks = new Marionette.Callbacks();
            this._finalizerCallbacks = new Marionette.Callbacks();
        }
    });

    // Type methods to create modules
    _.extend(Marionette.Module, {

        // Create a module, hanging off the app parameter as the parent object.
        create: function (app, moduleNames, moduleDefinition) {
            var that = this;
            var module = app;

            // get the custom args passed in after the module definition and
            // get rid of the module name and definition function
            var customArgs = slice.apply(arguments);
            customArgs.splice(0, 3);

            // split the module names and get the length
            moduleNames = moduleNames.split(".");
            var length = moduleNames.length;

            // store the module definition for the last module in the chain
            var moduleDefinitions = [];
            moduleDefinitions[length - 1] = moduleDefinition;

            // Loop through all the parts of the module definition
            _.each(moduleNames, function (moduleName, i) {
                var parentModule = module;
                module = that._getModule(parentModule, moduleName, app);
                that._addModuleDefinition(parentModule, module, moduleDefinitions[i], customArgs);
            });

            // Return the last module in the definition chain
            return module;
        },

        _getModule: function (parentModule, moduleName, app, def, args) {
            // Get an existing module of this name if we have one
            var module = parentModule[moduleName];

            if (!module) {
                // Create a new module if we don't have one
                module = new Marionette.Module(moduleName, app);
                parentModule[moduleName] = module;
                // store the module on the parent
                parentModule.submodules[moduleName] = module;
            }

            return module;
        },

        _addModuleDefinition: function (parentModule, module, def, args) {
            var fn;
            var startWithParent;

            if (_.isFunction(def)) {
                // if a function is supplied for the module definition
                fn = def;
                startWithParent = true;

            } else if (_.isObject(def)) {
                // if an object is supplied
                fn = def.define;
                startWithParent = def.startWithParent;

            } else {
                // if nothing is supplied
                startWithParent = true;
            }

            // add module definition if needed
            if (fn) {
                module.addDefinition(fn, args);
            }

            // `and` the two together, ensuring a single `false` will prevent it
            // from starting with the parent
            var tmp = module.startWithParent;
            module.startWithParent = module.startWithParent && startWithParent;

            // setup auto-start if needed
            if (module.startWithParent && !module.startWithParentIsConfigured) {

                // only configure this once
                module.startWithParentIsConfigured = true;

                // add the module initializer config
                parentModule.addInitializer(function (options) {
                    if (module.startWithParent) {
                        module.start(options);
                    }
                });

            }

        }
    });



    return Marionette;
})(Backbone, _, $ || window.jQuery || window.Zepto || window.ender);