<commit_before>module plat.ui {
    'use strict';

    /**
     * @name BindableTemplates
     * @memberof plat.ui
     * @kind class
     *
     * @description
     * The class which provides a way for {@link plat.ui.TemplateControl|TemplateControls} to bind a template
     * to a context. Useful for narrowing context without needing another
     * {@link plat.ui.TemplateControl|TemplateControl}. In addition, this object provides a performance increase because
     * it will only compile the template once. This object is also useful when a
     * {@link plat.ui.TemplateControl|TemplateControls} expects multiple configuration templates in its innerHTML. It can
     * separate those templates and reuse them accordingly.
     */
    export class BindableTemplates {
        /**
         * @name _ResourcesFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.ui.IResourcesFactory}
         *
         * @description
         * Reference to the {@link plat.ui.IResourcesFactory|IResourcesFactory} injectable.
         */
        protected _ResourcesFactory: IResourcesFactory = acquire(__ResourcesFactory);

        /**
         * @name _ControlFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.ui.IControlFactory}
         *
         * @description
         * Reference to the {@link plat.ui.IControlFactory|IControlFactory} injectable.
         */
        protected _ControlFactory: IControlFactory = acquire(__ControlFactory);

        /**
         * @name _TemplateControlFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.ui.ITemplateControlFactory}
         *
         * @description
         * Reference to the {@link plat.ui.ITemplateControlFactory|ITemplateControlFactory} injectable.
         */
        protected _TemplateControlFactory: ITemplateControlFactory = acquire(__TemplateControlFactory);

        /**
         * @name _ContextManager
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.observable.IContextManagerStatic}
         *
         * @description
         * Reference to the {@link plat.observable.IContextManagerStatic|IContextManagerStatic} injectable.
         */
        protected _ContextManager: observable.IContextManagerStatic = acquire(__ContextManagerStatic);

        /**
         * @name _Promise
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.async.IPromise}
         *
         * @description
         * Reference to the {@link plat.async.IPromise|IPromise} injectable.
         */
        protected _Promise: async.IPromise = acquire(__Promise);

        /**
         * @name _managerCache
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.storage.Cache<processing.ElementManager>}
         *
         * @description
         * Reference to a cache injectable that stores {@link plat.processing.ElementManager|ElementManagers}.
         */
        protected _managerCache: storage.Cache<processing.ElementManager> = acquire(__ManagerCache);

        /**
         * @name _document
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {Document}
         *
         * @description
         * Reference to the Document injectable.
         */
        protected _document: Document = acquire(__Document);

        /**
         * @name _ElementManagerFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.processing.IElementManagerFactory}
         *
         * @description
         * Reference to the {@link plat.processing.IElementManagerFactory|IElementManagerFactory} injectable.
         */
        protected _ElementManagerFactory: processing.IElementManagerFactory = acquire(__ElementManagerFactory);

        /**
         * @name _BindableTemplatesFactory
         * @memberof plat.processing.ElementManager
         * @kind property
         * @access protected
         *
         * @type {plat.ui.IBindableTemplatesFactory}
         *
         * @description
         * Reference to the {@link plat.ui.IBindableTemplatesFactory|BindableTemplatesFactory} injectable.
         */
        protected _BindableTemplatesFactory: IBindableTemplatesFactory = acquire(__BindableTemplatesFactory);

        /**
         * @name _log
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.debug.Log}
         * @description
         * Reference to the {@link plat.debug.Log|Log} injectable.
         */
        protected _log: debug.Log = acquire(__Log);

        /**
         * @name control
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access public
         *
         * @type {plat.ui.TemplateControl}
         *
         * @description
         * The control containing this {@link plat.ui.BindableTemplates|BindableTemplates} object.
         */
        control: TemplateControl;
        /**
         * @name templates
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access public
         *
         * @type {plat.IObject<plat.async.IThenable<DocumentFragment>>}
         *
         * @description
         * Stores promises that resolve to all the compiled templates for this object, ready to be bound to a data context.
         * All created templates are DocumentFragments, allowing an {@link plat.ui.TemplateControl|TemplateControl} to
         * easily insert the template into the DOM (without iterating over childNodes).
         */
        templates: IObject<async.IThenable<DocumentFragment>> = {};

        /**
         * @name cache
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access public
         *
         * @type {plat.IObject<plat.processing.ElementManager>}
         *
         * @description
         * A keyed cache of {@link plat.processing.ElementManager|ElementManagers} that represent the roots of compiled templates
         * created by this instance.
         */
        cache: IObject<processing.ElementManager> = {};

        /**
         * @name __compiledControls
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access private
         *
         * @type {Array<plat.ui.TemplateControl>}
         *
         * @description
         * A collection of all the controls created while compiling an added template. Useful during disposal.
         */
        private __compiledControls: Array<TemplateControl> = [];

        /**
         * @name create
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         * @variation 0
         *
         * @description
         * Creates a new instance of BindableTemplates and returns it. If a BindableTemplates is
         * passed in, it will use the properties on the original BindableTemplates.
         *
         * @param {plat.ui.TemplateControl} control The {@link plat.ui.TemplateControl|TemplateControl}
         * containing the new {@link plat.ui.BindableTemplates|BindableTemplates} object, used for data
         * context inheritance for templates.
         * @param {plat.ui.BindableTemplates} original? An optional {@link plat.ui.BindableTemplates|BindableTemplates}
         * object to copy.
         *
         * @returns {plat.ui.BindableTemplates} The newly instantiated {@link plat.ui.BindableTemplates|BindableTemplates} object.
         */
        static create(control: TemplateControl, original?: BindableTemplates): BindableTemplates;
        /**
         * @name create
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         * @variation 1
         *
         * @description
         * Creates a new instance of BindableTemplates and returns it. If a BindableTemplates is
         * passed in, it will use the properties on the original BindableTemplates.
         *
         * @param {plat.ui.TemplateControl} control The {@link plat.ui.TemplateControl|TemplateControl}
         * containing the new {@link plat.ui.BindableTemplates|BindableTemplates} object, used for data
         * context inheritance for templates.
         * @param {plat.ui.BindableTemplates} original? An optional {@link plat.ui.BindableTemplates|BindableTemplates}
         * object to copy.
         *
         * @returns {plat.ui.BindableTemplates} The newly instantiated {@link plat.ui.BindableTemplates|BindableTemplates} object.
         */
        static create(control: TemplateControl, original?: BindableTemplates): BindableTemplates {
            let bindableTemplates = new BindableTemplates();
            bindableTemplates.control = control;

            if (!isNull(original)) {
                bindableTemplates.templates = original.templates;
                bindableTemplates.cache = original.cache;
            }

            return bindableTemplates;
        }

        /**
         * @name dispose
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         *
         * @description
         * Clears the memory being held by control's bindableTemplates.
         *
         * @static
         * @param {plat.ui.TemplateControl} control The control whose bindableTemplates will be disposed.
         *
         * @returns {void}
         */
        static dispose(control: TemplateControl): void {
            if (isNull(control)) {
                return;
            }
            let instance = control.bindableTemplates;

            if (isNull(instance) || !isFunction(instance.dispose)) {
                return;
            }

            instance.dispose();
        }

        /**
         * @name isBoundControl
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         *
         * @description
         * Determines whether or not a control was created using bindableTemplates.
         *
         * @static
         * @param {plat.ui.TemplateControl} control The potential bound control.
         *
         * @returns {boolean} Whether or not the control is a bound control.
         */
        static isBoundControl(control: TemplateControl): boolean {
            if (isNull(control)) {
                return false;
            }

            let parent = control.parent;
            if (isNull(parent)) {
                return false;
            }

            return control.type.indexOf(parent.type + __BOUND_PREFIX) === 0;
        }

        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 0
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Element} template An Element representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Element, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 1
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Element} template An Element representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Element, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 2
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Array<Node>} template A node Array representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Array<Node>, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 3
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Array<Node>} template A node Array representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Array<Node>, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 4
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {NodeList} template A NodeList representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: NodeList, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 5
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {NodeList} template A NodeList representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: NodeList, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 6
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {DocumentFragment} template A DocumentFragment representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: DocumentFragment, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 7
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {DocumentFragment} template A DocumentFragment representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: DocumentFragment, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 8
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Node} template A Node representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Node, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 9
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Node} template A Node representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Node, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 10
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} template A template string representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: string, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 11
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} template A template string representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: string, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        once(template: any, relativeIdentifier?: any, resources?: IObject<IResource>): async.IThenable<DocumentFragment> {
            let fragment: DocumentFragment;
            if (isNull(template)) {
                return this._Promise.resolve(this._document.createDocumentFragment());
            } else if (isString(template)) {
                fragment = serializeHtml(template);
            } else if (isDocumentFragment(template)) {
                fragment = template;
            } else {
                fragment = this._document.createDocumentFragment();

                if (isNode(template)) {
                    fragment.appendChild(template);
                } else if (isArrayLike(template)) {
                    appendChildren(template, fragment);
                } else {
                    return this._Promise.resolve(fragment);
                }
            }

            if (!(isNull(relativeIdentifier) || isNumber(relativeIdentifier) || isString(relativeIdentifier))) {
                this._log.warn(this.control.type + ' cannot bind template with relativeIdentifier: ' + relativeIdentifier +
                    '. Identifier must be either a string or number');
                return;
            }

            let parent = this.control,
                controlManager = this._managerCache.read(parent.uid),
                manager = this._ElementManagerFactory.getInstance(),
                control = this._createBoundControl('', fragment, relativeIdentifier, resources),
                nodeMap = this._createNodeMap(control, fragment, relativeIdentifier);

            parent.controls.push(control);
            controlManager.children = [];
            manager.initialize(nodeMap, controlManager);
            manager.setUiControlTemplate();

            return manager.fulfillAndLoad().then((): DocumentFragment => {
                let _document = this._document;

                control.startNode = <Comment>fragment.insertBefore(_document.createComment(control.type + __START_NODE),
                    fragment.firstChild);
                control.endNode = <Comment>fragment.insertBefore(_document.createComment(control.type + __END_NODE),
                    null);

               return fragment;
            });
        }

        /**
         * @name bind
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 0
         *
         * @description
         * Method for linking a compiled template to a data context and returning a clone of the template,
         * with all new {@link plat.Control|Controls} created if the template contains controls. If no data context
         * is specified, it will be inherited.
         *
         * @param {string} key The key used to retrieve the template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is bound and
         * ready to return.
         */
        bind(key: string, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name bind
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 1
         *
         * @description
         * Method for linking a compiled template to a data context and returning a clone of the template,
         * with all new {@link plat.Control|Controls} created if the template contains controls. If no data context
         * is specified, it will be inherited.
         *
         * @param {string} key The key used to retrieve the template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is bound and
         * ready to return.
         */
        bind(key: string, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        bind(key: any, relativeIdentifier?: any, resources?: IObject<IResource>): async.IThenable<DocumentFragment> {
            return this._bind(key, relativeIdentifier, resources);
        }

        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 0
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {Element} template An Element representing the DOM template.
         *
         * @returns {void}
         */
        add(key: string, template: Element): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 1
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {Array<Node>} template A node Array representing the DOM template.
         *
         * @returns {void}
         */
        add(key: string, template: Array<Node>): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 2
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {NodeList} template A NodeList representing the DOM template.
         *
         * @returns {void}
         */
        add(key: string, template: NodeList): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 3
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {DocumentFragment} template A DocumentFragment representing the DOM template.
         *
         * @returns {void}
         */
        add(key: string, template: DocumentFragment): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 4
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {Node} template A Node representing the DOM template.
         *
         * @returns {void}
         */
        add(key: string, template: Node): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 5
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {string} template A template string representing the DOM template.
         *
         * @returns {void}
         */
        add(key: string, template: string): void;
        add(key: string, template: any): void {
            if (isEmpty(key)) {
                this._log.debug(this.control.type + ' must use a valid key to add a template to BindableTemplates.');
                return;
            }

            if (isNull(template)) {
                return;
            } else if (isString(template)) {
                this._compile(key, serializeHtml(template));
                return;
            } else if (isDocumentFragment(template)) {
                this._compile(key, template);
                return;
            }

            let fragment = this._document.createDocumentFragment();

            if (isNode(template)) {
                fragment.appendChild(template);
            } else if (isArrayLike(template)) {
                appendChildren(template, fragment);
            } else {
                return;
            }
<commit_msg>no longer overwriting bindableTemplates unless explicitly told to<commit_after>module plat.ui {
    'use strict';

    /**
     * @name BindableTemplates
     * @memberof plat.ui
     * @kind class
     *
     * @description
     * The class which provides a way for {@link plat.ui.TemplateControl|TemplateControls} to bind a template
     * to a context. Useful for narrowing context without needing another
     * {@link plat.ui.TemplateControl|TemplateControl}. In addition, this object provides a performance increase because
     * it will only compile the template once. This object is also useful when a
     * {@link plat.ui.TemplateControl|TemplateControls} expects multiple configuration templates in its innerHTML. It can
     * separate those templates and reuse them accordingly.
     */
    export class BindableTemplates {
        /**
         * @name _ResourcesFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.ui.IResourcesFactory}
         *
         * @description
         * Reference to the {@link plat.ui.IResourcesFactory|IResourcesFactory} injectable.
         */
        protected _ResourcesFactory: IResourcesFactory = acquire(__ResourcesFactory);

        /**
         * @name _ControlFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.ui.IControlFactory}
         *
         * @description
         * Reference to the {@link plat.ui.IControlFactory|IControlFactory} injectable.
         */
        protected _ControlFactory: IControlFactory = acquire(__ControlFactory);

        /**
         * @name _TemplateControlFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.ui.ITemplateControlFactory}
         *
         * @description
         * Reference to the {@link plat.ui.ITemplateControlFactory|ITemplateControlFactory} injectable.
         */
        protected _TemplateControlFactory: ITemplateControlFactory = acquire(__TemplateControlFactory);

        /**
         * @name _ContextManager
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.observable.IContextManagerStatic}
         *
         * @description
         * Reference to the {@link plat.observable.IContextManagerStatic|IContextManagerStatic} injectable.
         */
        protected _ContextManager: observable.IContextManagerStatic = acquire(__ContextManagerStatic);

        /**
         * @name _Promise
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.async.IPromise}
         *
         * @description
         * Reference to the {@link plat.async.IPromise|IPromise} injectable.
         */
        protected _Promise: async.IPromise = acquire(__Promise);

        /**
         * @name _managerCache
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.storage.Cache<processing.ElementManager>}
         *
         * @description
         * Reference to a cache injectable that stores {@link plat.processing.ElementManager|ElementManagers}.
         */
        protected _managerCache: storage.Cache<processing.ElementManager> = acquire(__ManagerCache);

        /**
         * @name _document
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {Document}
         *
         * @description
         * Reference to the Document injectable.
         */
        protected _document: Document = acquire(__Document);

        /**
         * @name _ElementManagerFactory
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.processing.IElementManagerFactory}
         *
         * @description
         * Reference to the {@link plat.processing.IElementManagerFactory|IElementManagerFactory} injectable.
         */
        protected _ElementManagerFactory: processing.IElementManagerFactory = acquire(__ElementManagerFactory);

        /**
         * @name _BindableTemplatesFactory
         * @memberof plat.processing.ElementManager
         * @kind property
         * @access protected
         *
         * @type {plat.ui.IBindableTemplatesFactory}
         *
         * @description
         * Reference to the {@link plat.ui.IBindableTemplatesFactory|BindableTemplatesFactory} injectable.
         */
        protected _BindableTemplatesFactory: IBindableTemplatesFactory = acquire(__BindableTemplatesFactory);

        /**
         * @name _log
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access protected
         *
         * @type {plat.debug.Log}
         * @description
         * Reference to the {@link plat.debug.Log|Log} injectable.
         */
        protected _log: debug.Log = acquire(__Log);

        /**
         * @name control
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access public
         *
         * @type {plat.ui.TemplateControl}
         *
         * @description
         * The control containing this {@link plat.ui.BindableTemplates|BindableTemplates} object.
         */
        control: TemplateControl;
        /**
         * @name templates
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access public
         *
         * @type {plat.IObject<plat.async.IThenable<DocumentFragment>>}
         *
         * @description
         * Stores promises that resolve to all the compiled templates for this object, ready to be bound to a data context.
         * All created templates are DocumentFragments, allowing an {@link plat.ui.TemplateControl|TemplateControl} to
         * easily insert the template into the DOM (without iterating over childNodes).
         */
        templates: IObject<async.IThenable<DocumentFragment>> = {};

        /**
         * @name cache
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access public
         *
         * @type {plat.IObject<plat.processing.ElementManager>}
         *
         * @description
         * A keyed cache of {@link plat.processing.ElementManager|ElementManagers} that represent the roots of compiled templates
         * created by this instance.
         */
        cache: IObject<processing.ElementManager> = {};

        /**
         * @name __compiledControls
         * @memberof plat.ui.BindableTemplates
         * @kind property
         * @access private
         *
         * @type {Array<plat.ui.TemplateControl>}
         *
         * @description
         * A collection of all the controls created while compiling an added template. Useful during disposal.
         */
        private __compiledControls: Array<TemplateControl> = [];

        /**
         * @name create
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         * @variation 0
         *
         * @description
         * Creates a new instance of BindableTemplates and returns it. If a BindableTemplates is
         * passed in, it will use the properties on the original BindableTemplates.
         *
         * @param {plat.ui.TemplateControl} control The {@link plat.ui.TemplateControl|TemplateControl}
         * containing the new {@link plat.ui.BindableTemplates|BindableTemplates} object, used for data
         * context inheritance for templates.
         * @param {plat.ui.BindableTemplates} original? An optional {@link plat.ui.BindableTemplates|BindableTemplates}
         * object to copy.
         *
         * @returns {plat.ui.BindableTemplates} The newly instantiated {@link plat.ui.BindableTemplates|BindableTemplates} object.
         */
        static create(control: TemplateControl, original?: BindableTemplates): BindableTemplates;
        /**
         * @name create
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         * @variation 1
         *
         * @description
         * Creates a new instance of BindableTemplates and returns it. If a BindableTemplates is
         * passed in, it will use the properties on the original BindableTemplates.
         *
         * @param {plat.ui.TemplateControl} control The {@link plat.ui.TemplateControl|TemplateControl}
         * containing the new {@link plat.ui.BindableTemplates|BindableTemplates} object, used for data
         * context inheritance for templates.
         * @param {plat.ui.BindableTemplates} original? An optional {@link plat.ui.BindableTemplates|BindableTemplates}
         * object to copy.
         *
         * @returns {plat.ui.BindableTemplates} The newly instantiated {@link plat.ui.BindableTemplates|BindableTemplates} object.
         */
        static create(control: TemplateControl, original?: BindableTemplates): BindableTemplates {
            let bindableTemplates = new BindableTemplates();
            bindableTemplates.control = control;

            if (!isNull(original)) {
                bindableTemplates.templates = original.templates;
                bindableTemplates.cache = original.cache;
            }

            return bindableTemplates;
        }

        /**
         * @name dispose
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         *
         * @description
         * Clears the memory being held by control's bindableTemplates.
         *
         * @static
         * @param {plat.ui.TemplateControl} control The control whose bindableTemplates will be disposed.
         *
         * @returns {void}
         */
        static dispose(control: TemplateControl): void {
            if (isNull(control)) {
                return;
            }
            let instance = control.bindableTemplates;

            if (isNull(instance) || !isFunction(instance.dispose)) {
                return;
            }

            instance.dispose();
        }

        /**
         * @name isBoundControl
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @static
         *
         * @description
         * Determines whether or not a control was created using bindableTemplates.
         *
         * @static
         * @param {plat.ui.TemplateControl} control The potential bound control.
         *
         * @returns {boolean} Whether or not the control is a bound control.
         */
        static isBoundControl(control: TemplateControl): boolean {
            if (isNull(control)) {
                return false;
            }

            let parent = control.parent;
            if (isNull(parent)) {
                return false;
            }

            return control.type.indexOf(parent.type + __BOUND_PREFIX) === 0;
        }

        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 0
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Element} template An Element representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Element, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 1
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Element} template An Element representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Element, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 2
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Array<Node>} template A node Array representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Array<Node>, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 3
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Array<Node>} template A node Array representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Array<Node>, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 4
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {NodeList} template A NodeList representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: NodeList, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 5
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {NodeList} template A NodeList representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: NodeList, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 6
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {DocumentFragment} template A DocumentFragment representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: DocumentFragment, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 7
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {DocumentFragment} template A DocumentFragment representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: DocumentFragment, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 8
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Node} template A Node representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Node, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 9
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {Node} template A Node representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: Node, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 10
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} template A template string representing the DOM template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: string, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name once
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 11
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} template A template string representing the DOM template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is compiled,
         * bound, and ready to return.
         */
        once(template: string, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        once(template: any, relativeIdentifier?: any, resources?: IObject<IResource>): async.IThenable<DocumentFragment> {
            let fragment: DocumentFragment;
            if (isNull(template)) {
                return this._Promise.resolve(this._document.createDocumentFragment());
            } else if (isString(template)) {
                fragment = serializeHtml(template);
            } else if (isDocumentFragment(template)) {
                fragment = template;
            } else {
                fragment = this._document.createDocumentFragment();

                if (isNode(template)) {
                    fragment.appendChild(template);
                } else if (isArrayLike(template)) {
                    appendChildren(template, fragment);
                } else {
                    return this._Promise.resolve(fragment);
                }
            }

            if (!(isNull(relativeIdentifier) || isNumber(relativeIdentifier) || isString(relativeIdentifier))) {
                this._log.warn(this.control.type + ' cannot bind template with relativeIdentifier: ' + relativeIdentifier +
                    '. Identifier must be either a string or number');
                return;
            }

            let parent = this.control,
                controlManager = this._managerCache.read(parent.uid),
                manager = this._ElementManagerFactory.getInstance(),
                control = this._createBoundControl('', fragment, relativeIdentifier, resources),
                nodeMap = this._createNodeMap(control, fragment, relativeIdentifier);

            parent.controls.push(control);
            controlManager.children = [];
            manager.initialize(nodeMap, controlManager);
            manager.setUiControlTemplate();

            return manager.fulfillAndLoad().then((): DocumentFragment => {
                let _document = this._document;

                control.startNode = <Comment>fragment.insertBefore(_document.createComment(control.type + __START_NODE),
                    fragment.firstChild);
                control.endNode = <Comment>fragment.insertBefore(_document.createComment(control.type + __END_NODE),
                    null);

               return fragment;
            });
        }

        /**
         * @name bind
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 0
         *
         * @description
         * Method for linking a compiled template to a data context and returning a clone of the template,
         * with all new {@link plat.Control|Controls} created if the template contains controls. If no data context
         * is specified, it will be inherited.
         *
         * @param {string} key The key used to retrieve the template.
         * @param {string} relativeIdentifier? The identifier string relative to this control's context
         * (e.g. 'foo.bar.baz' would signify the object this.context.foo.bar.baz). This is the
         * most efficient way of specifying context, else the framework has to search for the
         * object.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is bound and
         * ready to return.
         */
        bind(key: string, relativeIdentifier?: string, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        /**
         * @name bind
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 1
         *
         * @description
         * Method for linking a compiled template to a data context and returning a clone of the template,
         * with all new {@link plat.Control|Controls} created if the template contains controls. If no data context
         * is specified, it will be inherited.
         *
         * @param {string} key The key used to retrieve the template.
         * @param {number} relativeIdentifier? The identifier number relative to this control's context
         * (e.g. '1' would signify the object this.context[1]). Only necessary when context is an array.
         * @param {plat.IObject<plat.IResource>} resources? An object used as the resources for any top-level
         * controls created in the template.
         *
         * @returns {plat.async.IThenable<DocumentFragment>} A promise that resolves when the template is bound and
         * ready to return.
         */
        bind(key: string, relativeIdentifier?: number, resources?: IObject<IResource>): async.IThenable<DocumentFragment>;
        bind(key: any, relativeIdentifier?: any, resources?: IObject<IResource>): async.IThenable<DocumentFragment> {
            return this._bind(key, relativeIdentifier, resources);
        }

        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 0
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {Element} template An Element representing the DOM template.
         * @param {boolean} overwrite Specifies whether an already-existing template should be overwritten.
         *
         * @returns {void}
         */
        add(key: string, template: Element, overwrite?: boolean): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 1
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {Array<Node>} template A node Array representing the DOM template.
         * @param {boolean} overwrite Specifies whether an already-existing template should be overwritten.
         *
         * @returns {void}
         */
        add(key: string, template: Array<Node>, overwrite?: boolean): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 2
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {NodeList} template A NodeList representing the DOM template.
         * @param {boolean} overwrite Specifies whether an already-existing template should be overwritten.
         *
         * @returns {void}
         */
        add(key: string, template: NodeList, overwrite?: boolean): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 3
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {DocumentFragment} template A DocumentFragment representing the DOM template.
         * @param {boolean} overwrite Specifies whether an already-existing template should be overwritten.
         *
         * @returns {void}
         */
        add(key: string, template: DocumentFragment, overwrite?: boolean): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 4
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {Node} template A Node representing the DOM template.
         * @param {boolean} overwrite Specifies whether an already-existing template should be overwritten.
         *
         * @returns {void}
         */
        add(key: string, template: Node, overwrite?: boolean): void;
        /**
         * @name add
         * @memberof plat.ui.BindableTemplates
         * @kind function
         * @access public
         * @variation 5
         *
         * @description
         * Adds a template to this object. The template will be stored with the key,
         * and it will be transformed into a DocumentFragment.
         *
         * @param {string} key The key used to store the template.
         * @param {string} template A template string representing the DOM template.
         * @param {boolean} overwrite Specifies whether an already-existing template should be overwritten.
         *
         * @returns {void}
         */
        add(key: string, template: string, overwrite?: boolean): void;
        add(key: string, template: any, overwrite?: boolean): void {
            if (isEmpty(key)) {
                this._log.debug(this.control.type + ' must use a valid key to add a template to BindableTemplates.');
                return;
            }

            let templatePromise = this.templates[key];

            if (!isNull(templatePromise) && !overwrite) {
                return;
            }

            if (isNull(template)) {
                return;
            } else if (isString(template)) {
                this._compile(key, serializeHtml(template));
                return;
            } else if (isDocumentFragment(template)) {
                this._compile(key, template);
                return;
            }

            let fragment = this._document.createDocumentFragment();

            if (isNode(template)) {
                fragment.appendChild(template);
            } else if (isArrayLike(template)) {
                appendChildren(template, fragment);
            } else {
                return;
            }

{'fraction_non_alphanumeric': 0.08346555323590814, 'fraction_numerical': 0.0010855949895615866, 'mean_word_length': 2.0577495957102734, 'pattern_counts': {'":': 0, '<': 171, '<?xml version=': 0, '>': 173, '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': '1451393', 'n_tokens_mistral': 17840, 'n_tokens_neox': 17537, 'n_words': 5944}