<commit_before>//     Backbone.BaseView 0.3

//     (c) 2013 <NAME>, 1stdibs.com Inc.
//     Backbone.BaseView may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/1stdibs/backbone-base-and-form-view

/*global Backbone, window, jQuery, _ */
(function ($, Backbone, _, window) {
    "use strict";

    var
        // Finds globally dot noted namespaced objects from a string
        _stringToObj = function (str) {
            var arr = str.split('.'),
                obj = window[arr.shift()];

            while (arr.length && obj) {
                obj = obj[arr.shift()];
            }
            return obj;
        },
        slice = Array.prototype.slice,
        View = Backbone.View,
        BaseView,
        /**
         * Local constructor intended for use by {@link Backbone.BaseView}. Creates an object specifically
         * for manipulating subviews. Is created automatically by the BaseView instance and accessed through the
         * '.subs' property of the the instance.
         * @constructor SubViewManager
         * @class SubViewManager
         * @type {SubViewManager}
         * @param {object} subViewCfg An object with a configuration to add for subviews (see addConfig(map))
         * @param {Backbone.BaseView} parent The parent BaseView instance
         * @param [options]
         */
        SubViewManager = function (subViewCfg, parent, options) {
            this._subViews = {}; // Refers to configuration (construct, options)
            this.clear(true);
            this.parent = parent; // Should refer to parent BaseView instance

            // Set the options
            this.options = options || {};
            // Auto initialize a subview when config added
            this.autoInitSingletons = !!this.options.autoInitSingletons;
            // If true, then new subview configs and types will default to being singletons
            this.defaultToSingletons = this.options.defaultToSingletons;
            // Allow dot notation in 'get' method (if your config keys have dots, then set this to false)
            this.dotNotation = (this.options.dotNotation !== undefined) ? this.options.dotNotation : true;

            if (subViewCfg) {
                this.addConfig(subViewCfg);
            }
        };

    SubViewManager.prototype = {
       /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @class SubViewManager
         * @type {SubViewManager}
         * @method add
         * @param {Object} map
         *      An object with key's to refer to subViews and values that
         *      are View instances, options to pass to the constructor, or
         *      an array of either the previous two to add multiple subViews.
         *      If you pass options or an array of options, the SubViewManager
         *      will look for a configuration matching the key for these options
         *      and will initialize subviews based on the config, passing options
         *      to the constructor.
         * @param {Boolean} [singleton]
         *      True if the instances mapped to the keys should be singletons.
         *      If you pass options, the singleton param will be ignored.
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {String} name
         *      A string key to refer to the subViews with. Should match
         *      a key in the subView configuration. If not, a configuration
         *      will be set up with default values based on the instance
         *      passed.
         * @param {Backbone.View[]|object[]} arr
         *      An array of View instances or options. Instances will be
         *      appropriately associated with the key, options will be
         *      used to instantiate a subView based on the configuration
         *      matching the key
         * @param {Boolean} [singleton]
         *      True if the added views should be singletons
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {Backbone.View[]} arr
         *      An array of View instances. These will not be accessible
         *      by a type or key
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {String} name
         *      A string key to refer to the subView with
         * @param {Backbone.View} instance
         *      A View instance
         * @param {Object} [singleton]
         *      If you want the view matching this key to be a singleton
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {String} name
         *      A string key to refer to the subView with. Without an instance
         *      as the second param, this variant requires that a configuration
         *      to have been specified matching the 'name' with a constructor to
         *      initialize.
         * @param {Object} [options]
         *      An object that will be passed as the options parameter to the
         *      view on initialization.
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {Backbone.View} instance
         *      A Backbone.View instance to add as the subview
         * @return {SubViewManager}
         */
        add: function (name, instance, singleton) {
            var arr = (_.isArray(name)) ? name : (_.isArray(instance)) ? instance : undefined, // If its a simple array of subviews or configs
                map = (!arr && _.isObject(name) && name instanceof View === false) ? name : undefined, // If its a mapping of subviews
                viewOptions = (!arr && instance instanceof View === false) ? instance : undefined,
                key,
                i,
                len;

            if (map) {
                singleton = (typeof instance === 'boolean') ? instance : undefined;
                for (key in map) {
                    if (map.hasOwnProperty(key)) {
                        map[key] = (_.isArray(map[key])) ? map[key] : [map[key]];
                        len = map[key].length;
                        if (len && map[key][0] instanceof View) {
                            this._addInstance(key, map[key], singleton);
                        } else {
                            i = -1;
                            while (++i < len) {
                                this._init(key, map[key][i], singleton);
                            }
                        }
                    }
                }
                return this;
            }

            instance = (name instanceof View) ? name : instance;
            name = (typeof name === 'string' || typeof name === "number") ? name : undefined;
            singleton = (typeof singleton === 'boolean') ? singleton :
                    (!name && typeof instance === 'boolean') ? instance : undefined;

            if (viewOptions) {
                this._init(name, viewOptions, singleton);
                return this;
            }

            if (arr && (len = arr.length)) {
                if (arr[0] instanceof View) {
                    this._addInstance(name, arr, singleton);
                } else {
                    i = -1;
                    while (++i < len) {
                        this._init(name, arr[i], singleton);
                    }
                }

                return this;
            }

            if (instance) {
                this._addInstance(name, instance, singleton);
            } else if (name) {
                this._init(name, singleton);
            }
            return this;
        },
        /**
         * Add an configuration for a subview to the SubViewManager.
         * It can be instantiated later with the add function.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @class
         * @method addConfig
         * @param {String} name
         *      The name or type that you would like use to refer to subViews
         *      created with this config
         * @param {String|Function} construct
         *      The constructor function for this subView. If its a string, the
         *      string must resolve to a global name-spaced function in dot notation.
         *      (e.g. 'Backbone.imageUpload.View')
         * @param {String} [options]
         *      The options or base options you would like to pass to the constructor
         *      whenever it is initialized.
         * @param {String|HTMLElement} [location]
         *      If you want to be able to automatically place a subView's DOM element
         *      somewhere in the parent view, pass a selector or DOM element or $ instance
         *      here that can be used by jquery as a wrapper to append the subView $el
         * @param {Boolean} [singleton]
         *      If you want this view to be a singleton subView. A singleton subView
         *      will only allow one instance of it to be created.
         * @returns {SubViewManager}
         */
        /**
         * Add an configuration for a subview to the SubViewManager.
         * It can be instantiated later with the add function.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method addConfig
         * @param {Object} map
         *      A object of key names/types to config objects, so you can add multiple configs
         * @example
         * // A config object should have the following format:
         *      {
         *          construct:  // Constructor function or string version (i.e. "Backbone.BaseView")
         *          options:    // Any options you want to pass to the initialize function
         *          singleton:  // if the object should be configured as a singleton or not
         *          location:   // A string or jQuery instance in the parent view element.
         *                      // The subview el will be appended to that location
         *      }
         * @returns {SubViewManager}
         */
        /**
         * Add an configuration for a subview to the SubViewManager.
         * It can be instantiated later with the add function.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method addConfig
         * @param {String} name
         *      The name or type that you would like use to refer to subViews
         *      created with this config
         * @param {Object} config
         *      The configuration object (uses the format described above)
         * @returns {SubViewManager}
         */
        addConfig : function (name, config) {
            var map = (_.isObject(name) && !_.isArray(name)) ? name : false;
            if (map) {
                _.each(map, this._addConfig, this);
                return this;
            }

            return this._addConfig(config, name);
        },
        /**
         * Render all Subviews.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {object} [options]
         *      [options.appendTo] A selector, HTMLElement, or $ instance to append the subViews to
         *      [options.useLocation] 
         *          True if you want to append the subviews to the locations in their config if they 
         *          have one.
         *      [options.clearLocations]
         *          True if you want to use empty on the configured locations
         * @param {Boolean} [clearLocations]
         *      True if you want to remove all subView elements from the DOM before rendering
         *
         * @return {SubViewManager}
         */
        render: function (options) {
            options = options || {};
            var location = options.appendTo || options.useLocation;
            return this._render(this.subViews, location, options.clearLocations);
        },
        /**
         * Renders subviews and appends them to their 'locations' if they have one.
         * If you pass a appendTo param, views are appended to that location instead.
         * This is just a shortcut version of renderAppend({})
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {string|HTMLElement|$} [appendTo]
         *        Location to append the rendered subiews to
         * @param {object} [options] Other options (clearLocations)
         * @return {SubViewManager}
         */
        renderAppend: function (appendTo, options) {
            options = options || {};
            if (_.isObject(appendTo) && appendTo instanceof $ === false && !_.isElement(appendTo)) {
                options = appendTo;
                appendTo = options.appendTo;
            }
            return this._render(this.subViews, appendTo || true, options.clearLocations);
        },
        /**
         * Render a subView specified by a key (from their configuration key). The key will
         * retrieve subViews by looking for a type and then looking for singletons or
         * specific instance using the Model/View cid
         * 
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * 
         * @param {String|Backbone.Model|Backbone.View} key
         *      A key, type, View/Model cid, Model, or View to refer to a specific subView
         *      or subViews. For example, passing the view cid 'view4' will render only
         *      the view with that cid, and passing the type 'creatorNames' will render
         *      views matching the type 'creatorNames'.
         * @param {Boolean|String|HTMLElement} [useLocation]
         *      True if you want to use the subView's configuration 'location' to place the
         *      element the subView elems automatically. You can also pass a selector or
         *      DOM element that all subviews matched by the 'key' will be appended to
         *
         * @return {SubViewManager}
         */
        renderByKey: function (key, options) {
            var subViews = this.getByType(key) || this.get(key);
            if (!_.isArray(subViews)) { subViews = [subViews]; }
            return this._render(subViews, options.appendTo || options.useLocation, options.clearLocations);
        },
        /**
         * Returns a new SubViewManager instance with filtered list of subviews.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {string|Backbone.View[]|function} key
         *      The key or type used to refer to a subview or subviews, or a list
         *      of subViews with a type found in this SubViewManager config, or a function
         *      that will iterate over the subviews and return true if a subview
         *      should be included in the filtered SubViewManager instance.
         * @return {SubViewManager}
         */
        filteredSubs: function (key) {
            var i = -1, len, subViews,
                subMgr = new SubViewManager(null, this.parent, this.options);
            subMgr._subViews = this._subViews;
            subViews = (_.isArray(key)) ? key : (_.isFunction(key)) ? this.filter(key) : this.getByType(key);
            len = subViews.length;
            while (++i < len) {
                subMgr.add(subViews[i]._subviewtype, subViews[i]);
            }
            return subMgr;
        },
        /**
         * Iterate through every subView, calling a function or invoking a method on
         * each of them. If a subView has it's own subViews, then it will recursively
         * iterate over those as well. The context is switched to the subView calling
         * the function/method.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {String|Function} func 
         *        A string name of a method to call in the subviews or a function that
         *        will be called for each view
         * @param {Array} [args] An array of arguments to pass to the method/function
         * @return {SubViewManager}
         */
        descend: function (func, args) {
            var isFunc = _.isFunction(func),
                desc = function (subViews) {
                    var i = -1, len = subViews.length, subView, _func;
                    while (++i < len) {
                        subView = subViews[i];
                        _func = isFunc ? func : subView[func];
                        if (_func) {
                            if (args) { _func.apply(subView, args);
                                } else { _func.call(subViews[i]); }
                        }
                        if (subView.subViews && subView.subViews.length) {
                            desc(subView.subViews);
                        }
                    }
                };
            desc(this.subViews);
            return this;
        },
        /**
         * Clears all subViews and subView data off of the SubViewManager instance
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {Boolean} [preserveElems] If true, view $els are left on the DOM
         * @param {Boolean} [clearConfigs] If true, resets the subView configs as well
         * @return {SubViewManager}
         */
        clear: function (preserveElems, clearConfigs) {
            if (!preserveElems) {
                this.removeElems();
            }
            this.subViews = [];
            if (this.parent && this.parent.subViews) {
                this.parent.subViews = this.subViews;
            }
            this._subViewsByType = {};
            this._subViewSingletons = {};
            this._subViewsByCid = {};
            this._subViewsByModelCid = {};
            if (clearConfigs) {
                this._subViews = {};
            }
            return this;
        },
        /**
         * Remove a subView
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {String|Backbone.View|Backbone.Model} key
         * @param {Boolean} [preserveElems] If true, the View's element will not be removed from the DOM
         * @return {SubViewManager}
         */
        remove: function (key, preserveElems) {
            var subViews = (key && (typeof key === "string" || key.cid)) ? this.get(key) : key,
                len,
                i = -1;
            if (!subViews) { return this; }
            if (!_.isArray(subViews)) {
                subViews = [subViews];
            }
            len = subViews ? subViews.length : 0;
            if (!preserveElems) {
                this.removeElems(subViews);
            }
            if (len) {
                this.trigger('remove', subViews);
            }
            while (subViews && subViews.length) {
                this._remove(subViews.shift());
            }
            return this;
        },
        /**
         * Removes all subView '.el' element from the dom, or if passed a
         * list of subViews, removes only the elements in those.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param subViews
         * @return {SubViewManager}
         */
        removeElems: function (subViews) {
            subViews = subViews || this.subViews;

            var i = -1,
                len = subViews.length;
            while (++i < len) {
                subViews[i].remove();
            }
            return this;
        },
        /**
         * Get a subView instance or an array if multiple instances
         * match your key.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {Object|String} [key]
         *      The key to a subView singleton, the view's cid
         *      the associated model cid, the associated model itself,
         *      or the associated view itself. If your key is a
         *      string, you can use
         * @return {Backbone.View|Backbone.View[]}
         */
        get : function (key) {
            if (key.cid) {
                return this._subViewsByCid[key.cid] || this._subViewsByModelCid[key.cid];
            }
            if (key.indexOf('.') > -1 && this.dotNotation) {
                var segs = key.split('.'), view = this.parent;
                while (segs.length && view) { view = view.subs.get(segs.shift()); }
                return view;
            }

            return this._subViewSingletons[key] || this._subViewsByCid[key] ||
                this._subViewsByModelCid[key] || this._subViewsByType[key];
        },
        /**
         * Returns all views that match a type key, guarantees an array.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {String} type
         * @return {Backbone.View[]}
         */
        getByType : function (type) {
            if (this._subViewsByType[type]) {
                return this._subViewsByType[type];
            }
            return (this._subViewSingletons[type]) ? [this._subViewSingletons[type]] : [];
        },
        /**
         * Get the subviews type or key
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param subview
         * @return {String|Number}
         */
        getSubViewType : function (subview) {
            subview = (subview instanceof View === true) ? subview : this.get(subview);
            return subview._subviewtype;
        },
        /**
         * Get the subview at a specific index, based on the order
         * that the subViews were added or a custom sorted order.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param  {Number} index The index of the sub view
         * @return {Backbone.View}
         */
        at: function (index) {
            return this.subViews[index];
        },
        /**
         * Clears the html in all locations specified in the subview configs
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @return {SubViewManager}
         */
        clearLocations : function (type) {
            var confs = type ? _.pick(this._subViews, type) : this._subViews;
            _.each(confs, function (config) {
                this.parent.$(config.location).html('');
            }, this);
            return this;
        },
        _render : function (subViews, place, clearLocations) {
            var $appendTo,
                i = -1,
                len = subViews.length,
                location,
                $locations = {};
            if (place !== true) {
                $appendTo = place;
            }
            if (clearLocations) {
                this.clearLocations();
            }

            while (++i < len) {
                subViews[i].render();
                if ($appendTo) {
                    subViews[i].$el.appendTo($appendTo);
                } else if (place && (location = this._subViews[this.getSubViewType(subViews[i])].location)) {
                    if (typeof location === 'string') {
                        if (!$locations[location]) {
                            $locations[location] = this.parent.$(location);
                        }
                        location = $locations[location];
                    }
                    location.append(subViews[i].$el);
                }
            }
            return this;
        },
        _addInstance : function (key, subViews, singleton) {
            var i = -1, len, self = this;

            key = key || '_svid_' + _.size(this._subViews);

            if (self._subViewSingletons[key]) { return; }

            if (!_.isArray(subViews)) {
                subViews = [subViews];
            }

            len = subViews.length;

            if (!self._subViews[key] && subViews[0].constructor) {
                self._subViews[key] = {
                    options : subViews[0].options || {},
                    construct : subViews[0].constructor,
                    singleton : singleton
                };
            }

            singleton = (singleton === undefined) ? self._subViews[key].singleton : singleton;

            while (++i < len) {
                self._setInst(key, subViews[i], singleton);
            }
            return self;
        },
        _addConfig : function (config, name) {
            this._subViews[name] = config;
            if (this.autoInitSingletons && config.singleton) {
                return this._init(name);
            }
            return this;
        },
        _remove : function (subView, silent) {
            var i = -1,<commit_msg>Remove unused var and always return self in _addInstances for consistency<commit_after>//     Backbone.BaseView 0.3

//     (c) 2013 <NAME>, 1stdibs.com Inc.
//     Backbone.BaseView may be freely distributed under the MIT license.
//     For all details and documentation:
//     https://github.com/1stdibs/backbone-base-and-form-view

/*global Backbone, window, jQuery, _ */
(function ($, Backbone, _, window) {
    "use strict";

    var
        // Finds globally dot noted namespaced objects from a string
        _stringToObj = function (str) {
            var arr = str.split('.'),
                obj = window[arr.shift()];

            while (arr.length && obj) {
                obj = obj[arr.shift()];
            }
            return obj;
        },
        slice = Array.prototype.slice,
        View = Backbone.View,
        BaseView,
        /**
         * Local constructor intended for use by {@link Backbone.BaseView}. Creates an object specifically
         * for manipulating subviews. Is created automatically by the BaseView instance and accessed through the
         * '.subs' property of the the instance.
         * @constructor SubViewManager
         * @class SubViewManager
         * @type {SubViewManager}
         * @param {object} subViewCfg An object with a configuration to add for subviews (see addConfig(map))
         * @param {Backbone.BaseView} parent The parent BaseView instance
         * @param [options]
         */
        SubViewManager = function (subViewCfg, parent, options) {
            this._subViews = {}; // Refers to configuration (construct, options)
            this.clear(true);
            this.parent = parent; // Should refer to parent BaseView instance

            // Set the options
            this.options = options || {};
            // Auto initialize a subview when config added
            this.autoInitSingletons = !!this.options.autoInitSingletons;
            // If true, then new subview configs and types will default to being singletons
            this.defaultToSingletons = this.options.defaultToSingletons;
            // Allow dot notation in 'get' method (if your config keys have dots, then set this to false)
            this.dotNotation = (this.options.dotNotation !== undefined) ? this.options.dotNotation : true;

            if (subViewCfg) {
                this.addConfig(subViewCfg);
            }
        };

    SubViewManager.prototype = {
       /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @class SubViewManager
         * @type {SubViewManager}
         * @method add
         * @param {Object} map
         *      An object with key's to refer to subViews and values that
         *      are View instances, options to pass to the constructor, or
         *      an array of either the previous two to add multiple subViews.
         *      If you pass options or an array of options, the SubViewManager
         *      will look for a configuration matching the key for these options
         *      and will initialize subviews based on the config, passing options
         *      to the constructor.
         * @param {Boolean} [singleton]
         *      True if the instances mapped to the keys should be singletons.
         *      If you pass options, the singleton param will be ignored.
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {String} name
         *      A string key to refer to the subViews with. Should match
         *      a key in the subView configuration. If not, a configuration
         *      will be set up with default values based on the instance
         *      passed.
         * @param {Backbone.View[]|object[]} arr
         *      An array of View instances or options. Instances will be
         *      appropriately associated with the key, options will be
         *      used to instantiate a subView based on the configuration
         *      matching the key
         * @param {Boolean} [singleton]
         *      True if the added views should be singletons
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {Backbone.View[]} arr
         *      An array of View instances. These will not be accessible
         *      by a type or key
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {String} name
         *      A string key to refer to the subView with
         * @param {Backbone.View} instance
         *      A View instance
         * @param {Object} [singleton]
         *      If you want the view matching this key to be a singleton
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {String} name
         *      A string key to refer to the subView with. Without an instance
         *      as the second param, this variant requires that a configuration
         *      to have been specified matching the 'name' with a constructor to
         *      initialize.
         * @param {Object} [options]
         *      An object that will be passed as the options parameter to the
         *      view on initialization.
         * @return {SubViewManager}
         */
        /**
         * Adds a subView or subViews to the View's list of subViews. Calling
         * function must provide instances of views or configurations.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method add
         * @param {Backbone.View} instance
         *      A Backbone.View instance to add as the subview
         * @return {SubViewManager}
         */
        add: function (name, instance, singleton) {
            var arr = (_.isArray(name)) ? name : (_.isArray(instance)) ? instance : undefined, // If its a simple array of subviews or configs
                map = (!arr && _.isObject(name) && name instanceof View === false) ? name : undefined, // If its a mapping of subviews
                viewOptions = (!arr && instance instanceof View === false) ? instance : undefined,
                key,
                i,
                len;

            if (map) {
                singleton = (typeof instance === 'boolean') ? instance : undefined;
                for (key in map) {
                    if (map.hasOwnProperty(key)) {
                        map[key] = (_.isArray(map[key])) ? map[key] : [map[key]];
                        len = map[key].length;
                        if (len && map[key][0] instanceof View) {
                            this._addInstance(key, map[key], singleton);
                        } else {
                            i = -1;
                            while (++i < len) {
                                this._init(key, map[key][i], singleton);
                            }
                        }
                    }
                }
                return this;
            }

            instance = (name instanceof View) ? name : instance;
            name = (typeof name === 'string' || typeof name === "number") ? name : undefined;
            singleton = (typeof singleton === 'boolean') ? singleton :
                    (!name && typeof instance === 'boolean') ? instance : undefined;

            if (viewOptions) {
                this._init(name, viewOptions, singleton);
                return this;
            }

            if (arr && (len = arr.length)) {
                if (arr[0] instanceof View) {
                    this._addInstance(name, arr, singleton);
                } else {
                    i = -1;
                    while (++i < len) {
                        this._init(name, arr[i], singleton);
                    }
                }

                return this;
            }

            if (instance) {
                this._addInstance(name, instance, singleton);
            } else if (name) {
                this._init(name, singleton);
            }
            return this;
        },
        /**
         * Add an configuration for a subview to the SubViewManager.
         * It can be instantiated later with the add function.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @class
         * @method addConfig
         * @param {String} name
         *      The name or type that you would like use to refer to subViews
         *      created with this config
         * @param {String|Function} construct
         *      The constructor function for this subView. If its a string, the
         *      string must resolve to a global name-spaced function in dot notation.
         *      (e.g. 'Backbone.imageUpload.View')
         * @param {String} [options]
         *      The options or base options you would like to pass to the constructor
         *      whenever it is initialized.
         * @param {String|HTMLElement} [location]
         *      If you want to be able to automatically place a subView's DOM element
         *      somewhere in the parent view, pass a selector or DOM element or $ instance
         *      here that can be used by jquery as a wrapper to append the subView $el
         * @param {Boolean} [singleton]
         *      If you want this view to be a singleton subView. A singleton subView
         *      will only allow one instance of it to be created.
         * @returns {SubViewManager}
         */
        /**
         * Add an configuration for a subview to the SubViewManager.
         * It can be instantiated later with the add function.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method addConfig
         * @param {Object} map
         *      A object of key names/types to config objects, so you can add multiple configs
         * @example
         * // A config object should have the following format:
         *      {
         *          construct:  // Constructor function or string version (i.e. "Backbone.BaseView")
         *          options:    // Any options you want to pass to the initialize function
         *          singleton:  // if the object should be configured as a singleton or not
         *          location:   // A string or jQuery instance in the parent view element.
         *                      // The subview el will be appended to that location
         *      }
         * @returns {SubViewManager}
         */
        /**
         * Add an configuration for a subview to the SubViewManager.
         * It can be instantiated later with the add function.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @method addConfig
         * @param {String} name
         *      The name or type that you would like use to refer to subViews
         *      created with this config
         * @param {Object} config
         *      The configuration object (uses the format described above)
         * @returns {SubViewManager}
         */
        addConfig : function (name, config) {
            var map = (_.isObject(name) && !_.isArray(name)) ? name : false;
            if (map) {
                _.each(map, this._addConfig, this);
                return this;
            }

            return this._addConfig(config, name);
        },
        /**
         * Render all Subviews.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {object} [options]
         *      [options.appendTo] A selector, HTMLElement, or $ instance to append the subViews to
         *      [options.useLocation] 
         *          True if you want to append the subviews to the locations in their config if they 
         *          have one.
         *      [options.clearLocations]
         *          True if you want to use empty on the configured locations
         * @param {Boolean} [clearLocations]
         *      True if you want to remove all subView elements from the DOM before rendering
         *
         * @return {SubViewManager}
         */
        render: function (options) {
            options = options || {};
            var location = options.appendTo || options.useLocation;
            return this._render(this.subViews, location, options.clearLocations);
        },
        /**
         * Renders subviews and appends them to their 'locations' if they have one.
         * If you pass a appendTo param, views are appended to that location instead.
         * This is just a shortcut version of renderAppend({})
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {string|HTMLElement|$} [appendTo]
         *        Location to append the rendered subiews to
         * @param {object} [options] Other options (clearLocations)
         * @return {SubViewManager}
         */
        renderAppend: function (appendTo, options) {
            options = options || {};
            if (_.isObject(appendTo) && appendTo instanceof $ === false && !_.isElement(appendTo)) {
                options = appendTo;
                appendTo = options.appendTo;
            }
            return this._render(this.subViews, appendTo || true, options.clearLocations);
        },
        /**
         * Render a subView specified by a key (from their configuration key). The key will
         * retrieve subViews by looking for a type and then looking for singletons or
         * specific instance using the Model/View cid
         * 
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * 
         * @param {String|Backbone.Model|Backbone.View} key
         *      A key, type, View/Model cid, Model, or View to refer to a specific subView
         *      or subViews. For example, passing the view cid 'view4' will render only
         *      the view with that cid, and passing the type 'creatorNames' will render
         *      views matching the type 'creatorNames'.
         * @param {Boolean|String|HTMLElement} [useLocation]
         *      True if you want to use the subView's configuration 'location' to place the
         *      element the subView elems automatically. You can also pass a selector or
         *      DOM element that all subviews matched by the 'key' will be appended to
         *
         * @return {SubViewManager}
         */
        renderByKey: function (key, options) {
            var subViews = this.getByType(key) || this.get(key);
            if (!_.isArray(subViews)) { subViews = [subViews]; }
            return this._render(subViews, options.appendTo || options.useLocation, options.clearLocations);
        },
        /**
         * Returns a new SubViewManager instance with filtered list of subviews.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {string|Backbone.View[]|function} key
         *      The key or type used to refer to a subview or subviews, or a list
         *      of subViews with a type found in this SubViewManager config, or a function
         *      that will iterate over the subviews and return true if a subview
         *      should be included in the filtered SubViewManager instance.
         * @return {SubViewManager}
         */
        filteredSubs: function (key) {
            var i = -1, len, subViews,
                subMgr = new SubViewManager(null, this.parent, this.options);
            subMgr._subViews = this._subViews;
            subViews = (_.isArray(key)) ? key : (_.isFunction(key)) ? this.filter(key) : this.getByType(key);
            len = subViews.length;
            while (++i < len) {
                subMgr.add(subViews[i]._subviewtype, subViews[i]);
            }
            return subMgr;
        },
        /**
         * Iterate through every subView, calling a function or invoking a method on
         * each of them. If a subView has it's own subViews, then it will recursively
         * iterate over those as well. The context is switched to the subView calling
         * the function/method.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {String|Function} func 
         *        A string name of a method to call in the subviews or a function that
         *        will be called for each view
         * @param {Array} [args] An array of arguments to pass to the method/function
         * @return {SubViewManager}
         */
        descend: function (func, args) {
            var isFunc = _.isFunction(func),
                desc = function (subViews) {
                    var i = -1, len = subViews.length, subView, _func;
                    while (++i < len) {
                        subView = subViews[i];
                        _func = isFunc ? func : subView[func];
                        if (_func) {
                            if (args) { _func.apply(subView, args);
                                } else { _func.call(subViews[i]); }
                        }
                        if (subView.subViews && subView.subViews.length) {
                            desc(subView.subViews);
                        }
                    }
                };
            desc(this.subViews);
            return this;
        },
        /**
         * Clears all subViews and subView data off of the SubViewManager instance
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {Boolean} [preserveElems] If true, view $els are left on the DOM
         * @param {Boolean} [clearConfigs] If true, resets the subView configs as well
         * @return {SubViewManager}
         */
        clear: function (preserveElems, clearConfigs) {
            if (!preserveElems) {
                this.removeElems();
            }
            this.subViews = [];
            if (this.parent && this.parent.subViews) {
                this.parent.subViews = this.subViews;
            }
            this._subViewsByType = {};
            this._subViewSingletons = {};
            this._subViewsByCid = {};
            this._subViewsByModelCid = {};
            if (clearConfigs) {
                this._subViews = {};
            }
            return this;
        },
        /**
         * Remove a subView
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {String|Backbone.View|Backbone.Model} key
         * @param {Boolean} [preserveElems] If true, the View's element will not be removed from the DOM
         * @return {SubViewManager}
         */
        remove: function (key, preserveElems) {
            var subViews = (key && (typeof key === "string" || key.cid)) ? this.get(key) : key,
                len;
            if (!subViews) { return this; }
            if (!_.isArray(subViews)) {
                subViews = [subViews];
            }
            len = subViews ? subViews.length : 0;
            if (!preserveElems) {
                this.removeElems(subViews);
            }
            if (len) {
                this.trigger('remove', subViews);
            }
            while (subViews && subViews.length) {
                this._remove(subViews.shift());
            }
            return this;
        },
        /**
         * Removes all subView '.el' element from the dom, or if passed a
         * list of subViews, removes only the elements in those.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param subViews
         * @return {SubViewManager}
         */
        removeElems: function (subViews) {
            subViews = subViews || this.subViews;

            var i = -1,
                len = subViews.length;
            while (++i < len) {
                subViews[i].remove();
            }
            return this;
        },
        /**
         * Get a subView instance or an array if multiple instances
         * match your key.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {Object|String} [key]
         *      The key to a subView singleton, the view's cid
         *      the associated model cid, the associated model itself,
         *      or the associated view itself. If your key is a
         *      string, you can use
         * @return {Backbone.View|Backbone.View[]}
         */
        get : function (key) {
            if (key.cid) {
                return this._subViewsByCid[key.cid] || this._subViewsByModelCid[key.cid];
            }
            if (key.indexOf('.') > -1 && this.dotNotation) {
                var segs = key.split('.'), view = this.parent;
                while (segs.length && view) { view = view.subs.get(segs.shift()); }
                return view;
            }

            return this._subViewSingletons[key] || this._subViewsByCid[key] ||
                this._subViewsByModelCid[key] || this._subViewsByType[key];
        },
        /**
         * Returns all views that match a type key, guarantees an array.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param {String} type
         * @return {Backbone.View[]}
         */
        getByType : function (type) {
            if (this._subViewsByType[type]) {
                return this._subViewsByType[type];
            }
            return (this._subViewSingletons[type]) ? [this._subViewSingletons[type]] : [];
        },
        /**
         * Get the subviews type or key
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param subview
         * @return {String|Number}
         */
        getSubViewType : function (subview) {
            subview = (subview instanceof View === true) ? subview : this.get(subview);
            return subview._subviewtype;
        },
        /**
         * Get the subview at a specific index, based on the order
         * that the subViews were added or a custom sorted order.
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @param  {Number} index The index of the sub view
         * @return {Backbone.View}
         */
        at: function (index) {
            return this.subViews[index];
        },
        /**
         * Clears the html in all locations specified in the subview configs
         * @memberOf SubViewManager#
         * @type {SubViewManager}
         * @return {SubViewManager}
         */
        clearLocations : function (type) {
            var confs = type ? _.pick(this._subViews, type) : this._subViews;
            _.each(confs, function (config) {
                this.parent.$(config.location).html('');
            }, this);
            return this;
        },
        _render : function (subViews, place, clearLocations) {
            var $appendTo,
                i = -1,
                len = subViews.length,
                location,
                $locations = {};
            if (place !== true) {
                $appendTo = place;
            }
            if (clearLocations) {
                this.clearLocations();
            }

            while (++i < len) {
                subViews[i].render();
                if ($appendTo) {
                    subViews[i].$el.appendTo($appendTo);
                } else if (place && (location = this._subViews[this.getSubViewType(subViews[i])].location)) {
                    if (typeof location === 'string') {
                        if (!$locations[location]) {
                            $locations[location] = this.parent.$(location);
                        }
                        location = $locations[location];
                    }
                    location.append(subViews[i].$el);
                }
            }
            return this;
        },
        _addInstance : function (key, subViews, singleton) {
            var i = -1, len, self = this;

            key = key || '_svid_' + _.size(this._subViews);

            if (self._subViewSingletons[key]) { return self; }

            if (!_.isArray(subViews)) {
                subViews = [subViews];
            }

            len = subViews.length;

            if (!self._subViews[key] && subViews[0].constructor) {
                self._subViews[key] = {
                    options : subViews[0].options || {},
                    construct : subViews[0].constructor,
                    singleton : singleton
                };
            }

            singleton = (singleton === undefined) ? self._subViews[key].singleton : singleton;

            while (++i < len) {
                self._setInst(key, subViews[i], singleton);
            }
            return self;
        },
        _addConfig : function (config, name) {
            this._subViews[name] = config;
            if (this.autoInitSingletons && config.singleton) {
                return this._init(name);
            }
            return this;
        },
        _remove : function (subView, silent) {
            var i = -1,
{'fraction_non_alphanumeric': 0.0908844433255224, 'fraction_numerical': 0.0009489319673877259, 'mean_word_length': 1.5439944822149965, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 7, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3264814', 'n_tokens_mistral': 13219, 'n_tokens_neox': 12847, 'n_words': 4370}