<commit_before>/*!
 * backbone.layoutmanager.js v0.7.0
 * Copyright 2012, <NAME> (@tbranyen)
 * backbone.layoutmanager.js may be freely distributed under the MIT license.
 */
(function(window) {

"use strict";

// Hoisted, referenced at the bottom of the source.  This caches a list of all
// LayoutManager options at definition time.
var keys;

// Localize global dependency references.
var Backbone = window.Backbone;
var _ = window._;
var $ = window.$;

// Maintain references to the two `Backbone.View` functions that are
// overwritten so that they can be proxied.
var _configure = Backbone.View.prototype._configure;
var render = Backbone.View.prototype.render;

// Cache these methods for performance.
var aPush = Array.prototype.push;
var aConcat = Array.prototype.concat;

// LayoutManager is a wrapper around a `Backbone.View`.
var LayoutManager = Backbone.View.extend({
  // This named function allows for significantly easier debugging.
  constructor: function Layout(options) {
    // Options may not always be passed to the constructor, this ensures it is
    // always an object.
    options = options || {};

    // Grant this View superpowers.
    LayoutManager.setupView(this, options);

    // Have Backbone set up the rest of this View.
    Backbone.View.call(this, options);
  },

  // Shorthand to `setView` function with the `append` flag set.
  insertView: function(selector, view) {
    // If the `view` argument exists, then a selector was passed in.  This code
    // path will forward the selector on to `setView`.
    if (view) {
      return this.setView(selector, view, true);
    }

    // If no `view` argument is defined, then assume the first argument is the
    // View, somewhat now confusingly named `selector`.
    return this.setView(selector, true);
  },

  // Iterate over an object and ensure every value is wrapped in an array to
  // ensure they will be appended, then pass that object to `setViews`.
  insertViews: function(views) {
    _.each(views, function(view, selector) {
      views[selector] = _.isArray(view) ? view : [view];
    });

    return this.setViews(views);
  },

  // Returns the first View that matches the `getViews` filter function.
  getView: function(fn) {
    return this.getViews(fn).first().value();
  },

  // Provide a filter function to get a flattened array of all the subviews.
  // If the filter function is omitted it will return all subviews.
  getViews: function(fn) {
    // Generate an array of all top level (no deeply nested) Views flattened.
    var views = _.chain(this.views).map(function(view) {
      return _.isArray(view) ? view : [view];
    }, this).flatten().value();

    // If a filter function is provided, run it on all Views and return a
    // wrapped chain. Otherwise, simply return a wrapped chain of all Views.
    return _.chain(fn ? _.filter(views, fn) : views);
  },

  // This takes in a partial name and view instance and assigns them to
  // the internal collection of views.  If a view is not a LayoutManager
  // instance, then mix in the LayoutManager prototype.  This ensures
  // all Views can be used successfully.
  //
  // Must definitely wrap any render method passed in or defaults to a
  // typical render function `return layout(this).render()`.
  setView: function(name, view, append) {
    var manager, existing, options;
    // Parent view, the one you are setting a View on.
    var root = this;

    // If no name was passed, use an empty string and shift all arguments.
    if (typeof name !== "string") {
      append = view;
      view = name;
      name = "";
    }

    // If the parent views object doesn't exist... create it.
    this.views = this.views || {};

    // Shorthand the `__manager__` property.
    manager = view.__manager__;

    // Shorthand the View that potentially already exists.
    existing = this.views[name];

    // If the View has not been properly set up, throw an Error message
    // indicating that the View needs `manage: true` set.
    if (!manager) {
      throw new Error("Please set `manage` on the View with selector '" +
        name + "' to `true`.");
    }

    // Add reference to the parentView.
    manager.parent = root;

    // Add reference to the placement selector used.
    manager.selector = name;

    // Code path is less complex for Views that are not being appended.  Simply
    // remove existing Views and bail out with the assignment.
    if (!append) {
      // Ensure remove is called when swapping View's.
      if (existing) {
        // If the views are an array, iterate and remove each individually.
        _.each(aConcat.call([], existing), function(nestedView) {
          nestedView.remove();
        });
      }

      // Assign to main views object and return for chainability.
      return this.views[name] = view;
    }

    // Ensure this.views[name] is an array and push this View to the end.
    this.views[name] = aConcat.call([], existing || [], view);

    // Put the view into `append` mode.
    manager.append = true;

    return view;
  },

  // Allows the setting of multiple views instead of a single view.
  setViews: function(views) {
    // Iterate over all the views and use the View's view method to assign.
    _.each(views, function(view, name) {
      // If the view is an array put all views into insert mode.
      if (_.isArray(view)) {
        return _.each(view, function(view) {
          this.insertView(name, view);
        }, this);
      }

      // Assign each view using the view function.
      this.setView(name, view);
    }, this);

    // Allow for chaining
    return this;
  },

  // By default this should find all nested views and render them into
  // the this.el and call done once all of them have successfully been
  // resolved.
  //
  // This function returns a promise that can be chained to determine
  // once all subviews and main view have been rendered into the view.el.
  render: function() {
    var root = this;
    var manager = root.__manager__;
    var options = root._options();
    var viewDeferred = options.deferred();

    // Actually facilitate a render.
    function processRender(root) {
      // Triggered once the render has succeeded.
      function completeRender() {
        // If there is a parent, attach.
        if (manager.parent) {
          if (!options.contains(manager.parent.el, root.el)) {
            options.partial(manager.parent.el, manager.selector, root.el,
              manager.append);
          }
        }

        viewDeferred.resolveWith(root, [root.el]);
      }

      // The `_viewRender` method is broken out to abstract away from having
      // too much code in `processRender`.
      root._render(LayoutManager._viewRender, options).done(function() {
        // If there are no children to worry about, complete the render
        // instantly.
        if (!_.keys(root.views).length) {
          return completeRender();
        }

        // Create a list of promises to wait on until rendering is done. Since
        // this method will run on all children as well, its sufficient for a
        // full hierarchical. 
        var promises = _.map(root.views, function(view) {
          var append = _.isArray(view);

          // If items are being inserted, they will be in a non-zero length
          // Array.
          if (append && view.length) {
            // Only need to wait for the first View to complete, the rest will
            // be synchronous, by virtue of having the template cached.
            return view[0].render().pipe(function() {
              // Map over all the View's to be inserted and call render on them
              // all.  Once they have all resolved, resolve the other deferred.
              return options.when(_.map(view.slice(1), function(insertView) {
                return insertView.render();
              }));
            });
          }

          // Only return the fetch deferred, resolve the main deferred after
          // the element has been attached to it's parent.
          return !append ? view.render() : view;
        });

        // Once all nested Views have been rendered, resolve this View's
        // deferred.
        options.when(promises).done(completeRender);
      });
    }

    // Once the View has completed render, clean up remaining tasks.
    viewDeferred.done(function() {
      var next, done;
      var afterRender = options.afterRender;

      // Only process the queue if it exists.
      if (manager.queue) {
        if (next = manager.queue.shift()) {
          // Ensure that the next render is only called after all other `done`
          // handlers have completed.  This will prevent `render` callbacks
          // from firing out of order.
          viewDeferred.done(function() {
            next(root);
          });
        // Once the queue is depleted, remove it, the render process has
        // completed.
        } else {
          delete manager.queue;
        }
      }

      // This can be called immediately if the conditions allow, or it will
      // be deferred until a parent has finished rendering.
      done = function() {
        // Ensure events are always correctly bound after rendering.
        root.delegateEvents();

        // If an afterRender function is defined, call it.
        if (afterRender) {
          afterRender.call(root, root);
        }

        // Always emit an afterRender event.
        root.trigger("afterRender", root);
      };

      // If no parent exists, immediately call the done callback.
      return done.call(root);
    });

    // Existing render is currently happening if there is an existing queue, so
    // push a closure into the queue.
    if (manager.queue) {
      aPush.call(manager.queue, function() {
        processRender(root);
      });
    // Otherwise this is the first render being called and can safely execute
    // the entire code path.
    } else {
      // This queue is used to delay future renders.
      manager.queue = [];
      // Immediately run the first render.
      processRender(this);
    }
    // Add the View to the deferred so that `view.render().view.el` is
    // possible.
    viewDeferred.view = root;

    // This is the deferred that determines if the `render` function has
    // completed or not.
    return viewDeferred;
  },

  // Ensure the cleanup function is called whenever remove is called.
  remove: function() {
    // Force remove itself from its parent.
    LayoutManager._removeView(this, true);

    // Call the original remove function.
    return this._remove.apply(this, arguments);
  },

  // Merge instance and global options.
  _options: function() {
    // Instance overrides take precedence, fallback to prototype options.
    return _.extend({}, this, LayoutManager.prototype.options, this.options);
  }
},
{
  // Clearable cache.
  _cache: {},

  // Creates a deferred and returns a function to call when finished.
  _makeAsync: function(options, done) {
    var handler = options.deferred();

    // Used to handle asynchronous renders.
    handler.async = function() {
      handler._isAsync = true;

      return done;
    };

    return handler;
  },

  // This gets passed to all _render methods.  The `root` value here is passed
  // from the `manage(this).render()` line in the `_render` function
  _viewRender: function(root, options) {
    var url, contents, handler;
    var manager = root.__manager__;

    // Once the template is successfully fetched, use its contents to proceed.
    // Context argument is first, since it is bound for partial application
    // reasons.
    function done(context, contents) {
      // Ensure the cache is up-to-date.
      LayoutManager.cache(url, contents);

      // Render the View into the el property.
      if (contents) {
        options.html(root.el, options.render(contents, context));
      }

      // Resolve only the fetch (used internally) deferred with the View
      // element.
      handler.resolveWith(root, [root.el]);
    }

    return {
      // This `render` function is what gets called inside of the View render,
      // when `manage(this).render` is called.  Returns a promise that can be
      // used to know when the element has been rendered into its parent.
      render: function() {
        var context;
        var data = options.data || options.serialize;
        var template = root.template || options.template;

        // If data is a function, immediately call it.
        if (_.isFunction(data)) {
          data = data.call(root);
        }

        // This allows for `var done = this.async()` and then `done(contents)`.
        handler = LayoutManager._makeAsync(options, function(contents) {
          done(data, contents);
        });

        // Set the url to the prefix + the view's template property.
        if (_.isString(template)) {
          url = options.prefix + template;
        }

        // Check if contents are already cached and if they are, simply process
        // the template with the correct data.
        if (contents = LayoutManager.cache(url)) {
          done(data, contents, url);

          return handler;
        }

        // Fetch layout and template contents.
        if (_.isString(template)) {
          contents = options.fetch.call(handler, options.prefix + template);
        // If its not a string just pass the object/function/whatever.
        } else if (template != null) {
          contents = options.fetch.call(handler, template);
        }

        // If the function was synchronous, continue execution.
        if (!handler._isAsync) {
          done(data, contents);
        }

        return handler;
      }
    };
  },

  // Remove all nested Views.
  _removeViews: function(root, force) {
    // Shift arguments around.
    if (_.isBoolean(root)) {
      force = root;
      root = this;
    }

    // Allow removeView to be called on instances.
    root = root || this;

    // Iterate over all of the nested View's and remove.
    root.getViews().each(function(view) {
      LayoutManager._removeView(view, force);
    });
  },

  // Remove a single nested View.
  _removeView: function(view, force) {
    // Shorthand the manager for easier access.
    var manager = view.__manager__;
    // Test for keep.
    var keep = _.isBoolean(view.keep) ? view.keep : view.options.keep;
    // Only allow force if View is contained into a parent.
    force = manager.parent ? force : false;

    // Clean out the events.
    LayoutManager.cleanViews(view);

    // Only remove views that do not have `keep` attribute set, unless the
    // View is in `append` mode and the force flag is set.
    if (!keep && (manager.append === true || force)) {
      // Remove the View completely.
      view.$el.remove();

      // If this is an array of items remove items that are not marked to
      // keep.
      if (_.isArray(manager.parent.views[manager.selector])) {
        // Remove directly from the Array reference.
        return manager.parent.getView(function(view, i) {
          // If the managers match, splice off this View.
          if (view.__manager__ === manager) {
            manager.parent.views[manager.selector].splice(i, 1);
          }
        });
      }

      // Otherwise delete the parent selector.
      delete manager.parent.views[manager.selector];
    }
  },

  // Accept either a single view or an array of views to clean of all DOM
  // events internal model and collection references and all Backbone.Events.
  cleanViews: function(views) {
    // Clear out all existing views.
    _.each(aConcat.call([], views), function(view) {
      // Remove all custom events attached to this View.
      view.unbind();

      // Ensure all nested views are cleaned as well.
      if (view.views) {
        _.each(view.views, function(view) {
          LayoutManager.cleanViews(view);
        });
      }

      // Automatically unbind `model`.
      if (view.model instanceof Backbone.Model) {
        view.model.off(null, null, view);
      }

      // Automatically unbind `collection`.
      if (view.collection instanceof Backbone.Collection) {
        view.collection.off(null, null, view);
      }

      // If a custom cleanup method was provided on the view, call it after
      // the initial cleanup is done
      if (view.cleanup) {
        view.cleanup.call(view);
      }
    });
  },

  // Cache templates into LayoutManager._cache.
  cache: function(path, contents) {
    // If template path is found in the cache, return the contents.
    if (path in this._cache) {
      return this._cache[path];
    // Ensure path and contents aren't undefined.
    } else if (path != null && contents != null) {
      return this._cache[path] = contents;
    }

    // If the template is not in the cache, return undefined.
  },

  // This static method allows for global configuration of LayoutManager.
  configure: function(opts) {
    _.extend(LayoutManager.prototype.options, opts);

    // Allow LayoutManager to manage Backbone.View.prototype.
    if (opts.manage) {
      Backbone.View.prototype.manage = true;
    }
  },

  // Configure a View to work with the LayoutManager plugin.
  setupView: function(view, options) {
    // If the View has already been setup, no need to do it again.
    if (view.__manager__) {
      return;
    }

    var views, declaredViews, viewOptions;
    var proto = Backbone.LayoutManager.prototype;
    var viewOverrides = _.pick(view, keys);

    // Ensure necessary properties are set.
    _.defaults(view, {
      // Ensure a view always has a views object.
      views: {},

      // Internal state object used to store whether or not a View has been
      // taken over by layout manager and if it has been rendered into the DOM.
      __manager__: {},

      // Add the ability to remove all Views.
      _removeViews: LayoutManager._removeViews,

      // Add the ability to remove itself.
      _removeView: LayoutManager._removeView

    // Mix in all LayoutManager prototype properties as well.
    }, LayoutManager.prototype);

    // Extend the options with the prototype and passed options.
    options = view.options = _.defaults(options || {}, view.options,
      proto.options);

    // Ensure view events are properly copied over.
    viewOptions = _.pick(options, aConcat.call(["events"],
      _.values(options.events)));

    // Merge the View options into the View.
    _.extend(view, viewOptions);

    // If the View still has the Backbone.View#render method, remove it.  Don't
    // want it accidentally overriding the LM render.
    delete viewOverrides.render;

    // Pick out the specific properties that can be dynamically added at
    // runtime and ensure they are available on the view object.
    _.extend(options, viewOverrides);

    // By default the original Remove function is the Backbone.View one.
    view._remove = Backbone.View.prototype.remove;

    // Always use this render function when using LayoutManager.
    view._render = function(manage, options) {
      var renderDeferred;
      // Keep the view consistent between callbacks and deferreds.
      var view = this;
      // Shorthand the manager.
      var manager = view.__manager__;
      // Cache these properties.
      var beforeRender = options.beforeRender;

      // Ensure all nested Views are properly scrubbed if re-rendering.
      if (manager.hasRendered) {
        this._removeViews();
      }

      // If a beforeRender function is defined, call it.
      if (beforeRender) {
        beforeRender.call(this, this);
      }

      // Always emit a beforeRender event.
      this.trigger("beforeRender", this);

      // Render!
      renderDeferred = manage(this, options).render();

      // Once rendering is complete...
      renderDeferred.then(function() {
        // Set the view hasRendered.
        manager.hasRendered = true;
      });

      return renderDeferred;
    };

    // Ensure the render is always set correctly.
    view.render = LayoutManager.prototype.render;

    // If the user provided their own remove override, use that instead of the
    // default.
    if (view.remove !== proto.remove) {
      view._remove = view.remove;
      view.remove = proto.remove;
    }
    
    // Normalize views to exist on either instance or options, default to
    // options.
    views = options.views || view.views;

    // Set the internal views, only if selectors have been provided.
    if (_.keys(views).length) {
      // Keep original object declared containing Views.
      declaredViews = views;

      // Reset the property to avoid duplication or overwritting.
      view.views = {};

      // Set the declared Views.
      view.setViews(declaredViews);
    }

    // Ensure the template is mapped over.
    if (view.template) {
      options.template = view.template;

      // Remove it from the instance.
      delete view.template;
    }
  }
});

// Convenience assignment to make creating Layout's slightly shorter.
Backbone.Layout = Backbone.LayoutView = Backbone.LayoutManager = LayoutManager;
// Tack on the version.
LayoutManager.VERSION = "0.7.0";

// Override _configure to provide extra functionality that is necessary in
// order for the render function reference to be bound during initialize.
Backbone.View.prototype._configure = function() {
  // Run the original _configure.
  var retVal = _configure.apply(this, arguments);

  // If manage is set, do it!
  if (this.manage) {
    // Set up this View.
    LayoutManager.setupView(this);
  }

  // Act like nothing happened.
  return retVal;
};

// Default configuration options; designed to be overriden.
LayoutManager.prototype.options = {
  // Prefix template/layout paths.
  prefix: "",

  // Can be used to supply a different deferred implementation.
  deferred: function() {
    return $.Deferred();
  },

  // Fetch is passed a path and is expected to return template contents as a
  // function or string.
  fetch: function(path) {
    return _.template($(path).html());
  },

  // This is the most common way you will want to partially apply a view into
  // a layout.
  partial: function(root, name, el, append) {
    // If no selector is specified, assume the parent should be added to.
    var $root = name ? $(root).find(name) : $(root);

    // Use the append method if append argument is true.
    this[append ? "append" : "html"]($root, el);
  },

  // Override this with a custom HTML method, passed a root element and an
  // element to replace the innerHTML with.
  html: function(root, el) {
    $(root).html(el);
  },

  // Very similar to HTML except this one will appendChild.
  append: function(root, el) {
    $(root).append(el);
  },

  // Return a deferred for when all promises resolve/reject.
  when: function(promises) {
    return $.when.apply(null, promises);
  },

  // By default, render using underscore's templating.
  render: function(template, context) {
    return template(context);
  },

  // A method to determine if a View contains another.
  contains: function(parent, child) {
    return $.contains(parent, child);
  }
};

// Maintain a list of the keys at define time.
keys = _.keys(LayoutManager.prototype.options);

})(this);
<commit_msg>updated error message<commit_after>/*!
 * backbone.layoutmanager.js v0.7.0
 * Copyright 2012, <NAME> (@tbranyen)
 * backbone.layoutmanager.js may be freely distributed under the MIT license.
 */
(function(window) {

"use strict";

// Hoisted, referenced at the bottom of the source.  This caches a list of all
// LayoutManager options at definition time.
var keys;

// Localize global dependency references.
var Backbone = window.Backbone;
var _ = window._;
var $ = window.$;

// Maintain references to the two `Backbone.View` functions that are
// overwritten so that they can be proxied.
var _configure = Backbone.View.prototype._configure;
var render = Backbone.View.prototype.render;

// Cache these methods for performance.
var aPush = Array.prototype.push;
var aConcat = Array.prototype.concat;

// LayoutManager is a wrapper around a `Backbone.View`.
var LayoutManager = Backbone.View.extend({
  // This named function allows for significantly easier debugging.
  constructor: function Layout(options) {
    // Options may not always be passed to the constructor, this ensures it is
    // always an object.
    options = options || {};

    // Grant this View superpowers.
    LayoutManager.setupView(this, options);

    // Have Backbone set up the rest of this View.
    Backbone.View.call(this, options);
  },

  // Shorthand to `setView` function with the `append` flag set.
  insertView: function(selector, view) {
    // If the `view` argument exists, then a selector was passed in.  This code
    // path will forward the selector on to `setView`.
    if (view) {
      return this.setView(selector, view, true);
    }

    // If no `view` argument is defined, then assume the first argument is the
    // View, somewhat now confusingly named `selector`.
    return this.setView(selector, true);
  },

  // Iterate over an object and ensure every value is wrapped in an array to
  // ensure they will be appended, then pass that object to `setViews`.
  insertViews: function(views) {
    _.each(views, function(view, selector) {
      views[selector] = _.isArray(view) ? view : [view];
    });

    return this.setViews(views);
  },

  // Returns the first View that matches the `getViews` filter function.
  getView: function(fn) {
    return this.getViews(fn).first().value();
  },

  // Provide a filter function to get a flattened array of all the subviews.
  // If the filter function is omitted it will return all subviews.
  getViews: function(fn) {
    // Generate an array of all top level (no deeply nested) Views flattened.
    var views = _.chain(this.views).map(function(view) {
      return _.isArray(view) ? view : [view];
    }, this).flatten().value();

    // If a filter function is provided, run it on all Views and return a
    // wrapped chain. Otherwise, simply return a wrapped chain of all Views.
    return _.chain(fn ? _.filter(views, fn) : views);
  },

  // This takes in a partial name and view instance and assigns them to
  // the internal collection of views.  If a view is not a LayoutManager
  // instance, then mix in the LayoutManager prototype.  This ensures
  // all Views can be used successfully.
  //
  // Must definitely wrap any render method passed in or defaults to a
  // typical render function `return layout(this).render()`.
  setView: function(name, view, append) {
    var manager, existing, options;
    // Parent view, the one you are setting a View on.
    var root = this;

    // If no name was passed, use an empty string and shift all arguments.
    if (typeof name !== "string") {
      append = view;
      view = name;
      name = "";
    }

    // If the parent views object doesn't exist... create it.
    this.views = this.views || {};

    // Shorthand the `__manager__` property.
    manager = view.__manager__;

    // Shorthand the View that potentially already exists.
    existing = this.views[name];

    // If the View has not been properly set up, throw an Error message
    // indicating that the View needs `manage: true` set.
    if (!manager) {
      throw new Error("Please set `View#manage` property with selector '" +
        name + "' to `true`.");
    }

    // Add reference to the parentView.
    manager.parent = root;

    // Add reference to the placement selector used.
    manager.selector = name;

    // Code path is less complex for Views that are not being appended.  Simply
    // remove existing Views and bail out with the assignment.
    if (!append) {
      // Ensure remove is called when swapping View's.
      if (existing) {
        // If the views are an array, iterate and remove each individually.
        _.each(aConcat.call([], existing), function(nestedView) {
          nestedView.remove();
        });
      }

      // Assign to main views object and return for chainability.
      return this.views[name] = view;
    }

    // Ensure this.views[name] is an array and push this View to the end.
    this.views[name] = aConcat.call([], existing || [], view);

    // Put the view into `append` mode.
    manager.append = true;

    return view;
  },

  // Allows the setting of multiple views instead of a single view.
  setViews: function(views) {
    // Iterate over all the views and use the View's view method to assign.
    _.each(views, function(view, name) {
      // If the view is an array put all views into insert mode.
      if (_.isArray(view)) {
        return _.each(view, function(view) {
          this.insertView(name, view);
        }, this);
      }

      // Assign each view using the view function.
      this.setView(name, view);
    }, this);

    // Allow for chaining
    return this;
  },

  // By default this should find all nested views and render them into
  // the this.el and call done once all of them have successfully been
  // resolved.
  //
  // This function returns a promise that can be chained to determine
  // once all subviews and main view have been rendered into the view.el.
  render: function() {
    var root = this;
    var manager = root.__manager__;
    var options = root._options();
    var viewDeferred = options.deferred();

    // Actually facilitate a render.
    function processRender(root) {
      // Triggered once the render has succeeded.
      function completeRender() {
        // If there is a parent, attach.
        if (manager.parent) {
          if (!options.contains(manager.parent.el, root.el)) {
            options.partial(manager.parent.el, manager.selector, root.el,
              manager.append);
          }
        }

        viewDeferred.resolveWith(root, [root.el]);
      }

      // The `_viewRender` method is broken out to abstract away from having
      // too much code in `processRender`.
      root._render(LayoutManager._viewRender, options).done(function() {
        // If there are no children to worry about, complete the render
        // instantly.
        if (!_.keys(root.views).length) {
          return completeRender();
        }

        // Create a list of promises to wait on until rendering is done. Since
        // this method will run on all children as well, its sufficient for a
        // full hierarchical. 
        var promises = _.map(root.views, function(view) {
          var append = _.isArray(view);

          // If items are being inserted, they will be in a non-zero length
          // Array.
          if (append && view.length) {
            // Only need to wait for the first View to complete, the rest will
            // be synchronous, by virtue of having the template cached.
            return view[0].render().pipe(function() {
              // Map over all the View's to be inserted and call render on them
              // all.  Once they have all resolved, resolve the other deferred.
              return options.when(_.map(view.slice(1), function(insertView) {
                return insertView.render();
              }));
            });
          }

          // Only return the fetch deferred, resolve the main deferred after
          // the element has been attached to it's parent.
          return !append ? view.render() : view;
        });

        // Once all nested Views have been rendered, resolve this View's
        // deferred.
        options.when(promises).done(completeRender);
      });
    }

    // Once the View has completed render, clean up remaining tasks.
    viewDeferred.done(function() {
      var next, done;
      var afterRender = options.afterRender;

      // Only process the queue if it exists.
      if (manager.queue) {
        if (next = manager.queue.shift()) {
          // Ensure that the next render is only called after all other `done`
          // handlers have completed.  This will prevent `render` callbacks
          // from firing out of order.
          viewDeferred.done(function() {
            next(root);
          });
        // Once the queue is depleted, remove it, the render process has
        // completed.
        } else {
          delete manager.queue;
        }
      }

      // This can be called immediately if the conditions allow, or it will
      // be deferred until a parent has finished rendering.
      done = function() {
        // Ensure events are always correctly bound after rendering.
        root.delegateEvents();

        // If an afterRender function is defined, call it.
        if (afterRender) {
          afterRender.call(root, root);
        }

        // Always emit an afterRender event.
        root.trigger("afterRender", root);
      };

      // If no parent exists, immediately call the done callback.
      return done.call(root);
    });

    // Existing render is currently happening if there is an existing queue, so
    // push a closure into the queue.
    if (manager.queue) {
      aPush.call(manager.queue, function() {
        processRender(root);
      });
    // Otherwise this is the first render being called and can safely execute
    // the entire code path.
    } else {
      // This queue is used to delay future renders.
      manager.queue = [];
      // Immediately run the first render.
      processRender(this);
    }
    // Add the View to the deferred so that `view.render().view.el` is
    // possible.
    viewDeferred.view = root;

    // This is the deferred that determines if the `render` function has
    // completed or not.
    return viewDeferred;
  },

  // Ensure the cleanup function is called whenever remove is called.
  remove: function() {
    // Force remove itself from its parent.
    LayoutManager._removeView(this, true);

    // Call the original remove function.
    return this._remove.apply(this, arguments);
  },

  // Merge instance and global options.
  _options: function() {
    // Instance overrides take precedence, fallback to prototype options.
    return _.extend({}, this, LayoutManager.prototype.options, this.options);
  }
},
{
  // Clearable cache.
  _cache: {},

  // Creates a deferred and returns a function to call when finished.
  _makeAsync: function(options, done) {
    var handler = options.deferred();

    // Used to handle asynchronous renders.
    handler.async = function() {
      handler._isAsync = true;

      return done;
    };

    return handler;
  },

  // This gets passed to all _render methods.  The `root` value here is passed
  // from the `manage(this).render()` line in the `_render` function
  _viewRender: function(root, options) {
    var url, contents, handler;
    var manager = root.__manager__;

    // Once the template is successfully fetched, use its contents to proceed.
    // Context argument is first, since it is bound for partial application
    // reasons.
    function done(context, contents) {
      // Ensure the cache is up-to-date.
      LayoutManager.cache(url, contents);

      // Render the View into the el property.
      if (contents) {
        options.html(root.el, options.render(contents, context));
      }

      // Resolve only the fetch (used internally) deferred with the View
      // element.
      handler.resolveWith(root, [root.el]);
    }

    return {
      // This `render` function is what gets called inside of the View render,
      // when `manage(this).render` is called.  Returns a promise that can be
      // used to know when the element has been rendered into its parent.
      render: function() {
        var context;
        var data = options.data || options.serialize;
        var template = root.template || options.template;

        // If data is a function, immediately call it.
        if (_.isFunction(data)) {
          data = data.call(root);
        }

        // This allows for `var done = this.async()` and then `done(contents)`.
        handler = LayoutManager._makeAsync(options, function(contents) {
          done(data, contents);
        });

        // Set the url to the prefix + the view's template property.
        if (_.isString(template)) {
          url = options.prefix + template;
        }

        // Check if contents are already cached and if they are, simply process
        // the template with the correct data.
        if (contents = LayoutManager.cache(url)) {
          done(data, contents, url);

          return handler;
        }

        // Fetch layout and template contents.
        if (_.isString(template)) {
          contents = options.fetch.call(handler, options.prefix + template);
        // If its not a string just pass the object/function/whatever.
        } else if (template != null) {
          contents = options.fetch.call(handler, template);
        }

        // If the function was synchronous, continue execution.
        if (!handler._isAsync) {
          done(data, contents);
        }

        return handler;
      }
    };
  },

  // Remove all nested Views.
  _removeViews: function(root, force) {
    // Shift arguments around.
    if (_.isBoolean(root)) {
      force = root;
      root = this;
    }

    // Allow removeView to be called on instances.
    root = root || this;

    // Iterate over all of the nested View's and remove.
    root.getViews().each(function(view) {
      LayoutManager._removeView(view, force);
    });
  },

  // Remove a single nested View.
  _removeView: function(view, force) {
    // Shorthand the manager for easier access.
    var manager = view.__manager__;
    // Test for keep.
    var keep = _.isBoolean(view.keep) ? view.keep : view.options.keep;
    // Only allow force if View is contained into a parent.
    force = manager.parent ? force : false;

    // Clean out the events.
    LayoutManager.cleanViews(view);

    // Only remove views that do not have `keep` attribute set, unless the
    // View is in `append` mode and the force flag is set.
    if (!keep && (manager.append === true || force)) {
      // Remove the View completely.
      view.$el.remove();

      // If this is an array of items remove items that are not marked to
      // keep.
      if (_.isArray(manager.parent.views[manager.selector])) {
        // Remove directly from the Array reference.
        return manager.parent.getView(function(view, i) {
          // If the managers match, splice off this View.
          if (view.__manager__ === manager) {
            manager.parent.views[manager.selector].splice(i, 1);
          }
        });
      }

      // Otherwise delete the parent selector.
      delete manager.parent.views[manager.selector];
    }
  },

  // Accept either a single view or an array of views to clean of all DOM
  // events internal model and collection references and all Backbone.Events.
  cleanViews: function(views) {
    // Clear out all existing views.
    _.each(aConcat.call([], views), function(view) {
      // Remove all custom events attached to this View.
      view.unbind();

      // Ensure all nested views are cleaned as well.
      if (view.views) {
        _.each(view.views, function(view) {
          LayoutManager.cleanViews(view);
        });
      }

      // Automatically unbind `model`.
      if (view.model instanceof Backbone.Model) {
        view.model.off(null, null, view);
      }

      // Automatically unbind `collection`.
      if (view.collection instanceof Backbone.Collection) {
        view.collection.off(null, null, view);
      }

      // If a custom cleanup method was provided on the view, call it after
      // the initial cleanup is done
      if (view.cleanup) {
        view.cleanup.call(view);
      }
    });
  },

  // Cache templates into LayoutManager._cache.
  cache: function(path, contents) {
    // If template path is found in the cache, return the contents.
    if (path in this._cache) {
      return this._cache[path];
    // Ensure path and contents aren't undefined.
    } else if (path != null && contents != null) {
      return this._cache[path] = contents;
    }

    // If the template is not in the cache, return undefined.
  },

  // This static method allows for global configuration of LayoutManager.
  configure: function(opts) {
    _.extend(LayoutManager.prototype.options, opts);

    // Allow LayoutManager to manage Backbone.View.prototype.
    if (opts.manage) {
      Backbone.View.prototype.manage = true;
    }
  },

  // Configure a View to work with the LayoutManager plugin.
  setupView: function(view, options) {
    // If the View has already been setup, no need to do it again.
    if (view.__manager__) {
      return;
    }

    var views, declaredViews, viewOptions;
    var proto = Backbone.LayoutManager.prototype;
    var viewOverrides = _.pick(view, keys);

    // Ensure necessary properties are set.
    _.defaults(view, {
      // Ensure a view always has a views object.
      views: {},

      // Internal state object used to store whether or not a View has been
      // taken over by layout manager and if it has been rendered into the DOM.
      __manager__: {},

      // Add the ability to remove all Views.
      _removeViews: LayoutManager._removeViews,

      // Add the ability to remove itself.
      _removeView: LayoutManager._removeView

    // Mix in all LayoutManager prototype properties as well.
    }, LayoutManager.prototype);

    // Extend the options with the prototype and passed options.
    options = view.options = _.defaults(options || {}, view.options,
      proto.options);

    // Ensure view events are properly copied over.
    viewOptions = _.pick(options, aConcat.call(["events"],
      _.values(options.events)));

    // Merge the View options into the View.
    _.extend(view, viewOptions);

    // If the View still has the Backbone.View#render method, remove it.  Don't
    // want it accidentally overriding the LM render.
    delete viewOverrides.render;

    // Pick out the specific properties that can be dynamically added at
    // runtime and ensure they are available on the view object.
    _.extend(options, viewOverrides);

    // By default the original Remove function is the Backbone.View one.
    view._remove = Backbone.View.prototype.remove;

    // Always use this render function when using LayoutManager.
    view._render = function(manage, options) {
      var renderDeferred;
      // Keep the view consistent between callbacks and deferreds.
      var view = this;
      // Shorthand the manager.
      var manager = view.__manager__;
      // Cache these properties.
      var beforeRender = options.beforeRender;

      // Ensure all nested Views are properly scrubbed if re-rendering.
      if (manager.hasRendered) {
        this._removeViews();
      }

      // If a beforeRender function is defined, call it.
      if (beforeRender) {
        beforeRender.call(this, this);
      }

      // Always emit a beforeRender event.
      this.trigger("beforeRender", this);

      // Render!
      renderDeferred = manage(this, options).render();

      // Once rendering is complete...
      renderDeferred.then(function() {
        // Set the view hasRendered.
        manager.hasRendered = true;
      });

      return renderDeferred;
    };

    // Ensure the render is always set correctly.
    view.render = LayoutManager.prototype.render;

    // If the user provided their own remove override, use that instead of the
    // default.
    if (view.remove !== proto.remove) {
      view._remove = view.remove;
      view.remove = proto.remove;
    }
    
    // Normalize views to exist on either instance or options, default to
    // options.
    views = options.views || view.views;

    // Set the internal views, only if selectors have been provided.
    if (_.keys(views).length) {
      // Keep original object declared containing Views.
      declaredViews = views;

      // Reset the property to avoid duplication or overwritting.
      view.views = {};

      // Set the declared Views.
      view.setViews(declaredViews);
    }

    // Ensure the template is mapped over.
    if (view.template) {
      options.template = view.template;

      // Remove it from the instance.
      delete view.template;
    }
  }
});

// Convenience assignment to make creating Layout's slightly shorter.
Backbone.Layout = Backbone.LayoutView = Backbone.LayoutManager = LayoutManager;
// Tack on the version.
LayoutManager.VERSION = "0.7.0";

// Override _configure to provide extra functionality that is necessary in
// order for the render function reference to be bound during initialize.
Backbone.View.prototype._configure = function() {
  // Run the original _configure.
  var retVal = _configure.apply(this, arguments);

  // If manage is set, do it!
  if (this.manage) {
    // Set up this View.
    LayoutManager.setupView(this);
  }

  // Act like nothing happened.
  return retVal;
};

// Default configuration options; designed to be overriden.
LayoutManager.prototype.options = {
  // Prefix template/layout paths.
  prefix: "",

  // Can be used to supply a different deferred implementation.
  deferred: function() {
    return $.Deferred();
  },

  // Fetch is passed a path and is expected to return template contents as a
  // function or string.
  fetch: function(path) {
    return _.template($(path).html());
  },

  // This is the most common way you will want to partially apply a view into
  // a layout.
  partial: function(root, name, el, append) {
    // If no selector is specified, assume the parent should be added to.
    var $root = name ? $(root).find(name) : $(root);

    // Use the append method if append argument is true.
    this[append ? "append" : "html"]($root, el);
  },

  // Override this with a custom HTML method, passed a root element and an
  // element to replace the innerHTML with.
  html: function(root, el) {
    $(root).html(el);
  },

  // Very similar to HTML except this one will appendChild.
  append: function(root, el) {
    $(root).append(el);
  },

  // Return a deferred for when all promises resolve/reject.
  when: function(promises) {
    return $.when.apply(null, promises);
  },

  // By default, render using underscore's templating.
  render: function(template, context) {
    return template(context);
  },

  // A method to determine if a View contains another.
  contains: function(parent, child) {
    return $.contains(parent, child);
  }
};

// Maintain a list of the keys at define time.
keys = _.keys(LayoutManager.prototype.options);

})(this);

{'fraction_non_alphanumeric': 0.10101553423124919, 'fraction_numerical': 0.0005594044494169285, 'mean_word_length': 2.3761168010459794, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4194552', 'n_tokens_mistral': 12569, 'n_tokens_neox': 12212, 'n_words': 4836}