    /**
     * This mixin enables classes to declare relationships to child elements and provides the
     * mechanics for acquiring the {@link Ext.Element elements} and storing them on an object
     * instance as properties.
     *
     * This class is used by {@link Ext.Component components} and {@link Ext.layout.container.Container container layouts} to
     * manage their child elements.
     *
     * A typical component that uses these features might look something like this:
     *
     *      Ext.define('Ext.ux.SomeComponent', {
     *          extend: 'Ext.Component',
     *
     *          childEls: [
     *              'bodyEl'
     *          ],
     *
     *          renderTpl: [
     *              '<div id="{id}-bodyEl"></div>'
     *          ],
     *
     *          // ...
     *      });
     *
     * The `childEls` array lists one or more relationships to child elements managed by the
     * component. The items in this array can be either of the following types:
     *
     * - String: the id suffix and property name in one. For example, "bodyEl" in the above
     * example means a "bodyEl" property will be added to the instance with the result of
     * {@link Ext#get} given "componentId-bodyEl" where "componentId" is the component instance's
     * id.
     * - Object: with a `name` property that names the instance property for the element, and
     * one of the following additional properties:
     *      - `id`: The full id of the child element.
     *      - `itemId`: The suffix part of the id to which "componentId-" is prepended.
     *      - `select`: A selector that will be passed to {@link Ext#select}.
     *      - `selectNode`: A selector that will be passed to {@link Ext.DomQuery#selectNode}.
     *
     * The example above could have used this instead to achieve the same result:
     *
     *      childEls: [
     *          { name: 'bodyEl', itemId: 'bodyEl' }
     *      ]
     *
     * When using `select`, the property will be an instance of {@link Ext.CompositeElement}. In
     * all other cases, the property will be an {@link Ext.Element} or `null` if not found.
     *
     * Care should be taken when using `select` or `selectNode` to find child elements. The
     * following issues should be considered:
     *
     * - Performance: using selectors can be slower than id lookup by a factor 10x or more.
     * - Over-selecting: selectors are applied after the DOM elements for all children have
     * been rendered, so selectors can match elements from child components (including nested
     * versions of the same component) accidentally.
     *
     * This above issues are most important when using `select` since it returns multiple
     * elements.
     *
     * **IMPORTANT**
     * Unlike a `renderTpl` where there is a single value for an instance, `childEls` are aggregated
     * up the class hierarchy so that they are effectively inherited. In other words, if a
     * class where to derive from `Ext.ux.SomeComponent` in the example above, it could also
     * have a `childEls` property in the same way as `Ext.ux.SomeComponent`.
     *
     *      Ext.define('Ext.ux.AnotherComponent', {
     *          extend: 'Ext.ux.SomeComponent',
     *
     *          childEls: [
     *              // 'bodyEl' is inherited
     *              'innerEl'
     *          ],
     *
     *          renderTpl: [
     *              '<div id="{id}-bodyEl">'
     *                  '<div id="{id}-innerEl"></div>'
     *              '</div>'
     *          ],
     *
     *          // ...
     *      });
     *
     * The `renderTpl` contains both child elements and unites them in the desired markup, but
     * the `childEls` only contains the new child element. The {@link #applyChildEls} method
     * takes care of looking up all `childEls` for an instance and considers `childEls`
     * properties on all the super classes and mixins.
     *
     * @private
     */
    Ext.define('Ext.util.ElementContainer', {

        childEls: [
            // empty - this solves a couple problems:
            //  1. It ensures that all classes have a childEls (avoid null ptr)
            //  2. It prevents mixins from smashing on their own childEls (these are gathered
            //      specifically)
        ],

        constructor: function () {
            var me = this,
                childEls;

            // if we have configured childEls, we need to merge them with those from this
            // class, its bases and the set of mixins...
            if (me.hasOwnProperty('childEls')) {
                childEls = me.childEls;
                delete me.childEls;

                me.addChildEls.apply(me, childEls);
            }
        },

        destroy: function () {
            var me = this,
                childEls = me.getChildEls(),
                child, childName, i, k;

            for (i = childEls.length; i--; ) {
                childName = childEls[i];
                if (typeof childName != 'string') {
                    childName = childName.name;
                }

                child = me[childName];
                if (child) {
                    me[childName] = null; // better than delete since that changes the "shape"
                    child.remove();
                }
            }
        },

        /**
         * Adds each argument passed to this method to the {@link Ext.AbstractComponent#cfg-childEls childEls} array.
         */
        addChildEls: function () {
            var me = this,
                args = arguments;

            if (me.hasOwnProperty('childEls')) {
                me.childEls.push.apply(me.childEls, args);
            } else {
                me.childEls = me.getChildEls().concat(Array.prototype.slice.call(args));
            }

            me.prune(me.childEls, false);
        },

        /**
         * Sets references to elements inside the component.
         * @private
         */
        applyChildEls: function(el, id) {
            var me = this,
                childEls = me.getChildEls(),
                baseId, childName, i, selector, value;

            baseId = (id || me.id) + '-';
            for (i = childEls.length; i--; ) {
                childName = childEls[i];

                if (typeof childName == 'string') {
                    // We don't use Ext.get because that is 3x (or more) slower on IE6-8. Since
                    // we know the el's are children of our el we use getById instead:
                    value = el.getById(baseId + childName);
                } else {
                    if ((selector = childName.select)) {
                        value = Ext.select(selector, true, el.dom); // a CompositeElement
                    } else if ((selector = childName.selectNode)) {
                        value = Ext.get(Ext.DomQuery.selectNode(selector, el.dom));
                    } else {
                        // see above re:getById...
                        value = el.getById(childName.id || (baseId + childName.itemId));
                    }

                    childName = childName.name;
                }

                me[childName] = value;
            }
        },

        getChildEls: function () {
            var me = this,
                self;

            // If an instance has its own childEls, that is the complete set:
            if (me.hasOwnProperty('childEls')) {
                return me.childEls;
            }

            // Typically, however, the childEls is a class-level concept, so check to see if
            // we have cached the complete set on the class:
            self = me.self;
            return self.$childEls || me.getClassChildEls(self);
        },

        getClassChildEls: function (cls) {
            var me = this,
                result = cls.$childEls,
                childEls, i, length, forked, mixin, mixins, name, parts, proto, supr, superMixins;

            if (!result) {
                // We put the various childEls arrays into parts in the order of superclass,
                // new mixins and finally from cls. These parts can be null or undefined and
                // we will skip them later.

                supr = cls.superclass;
                if (supr) {
                    supr = supr.self;
                    parts = [supr.$childEls || me.getClassChildEls(supr)]; // super+mixins
                    superMixins = supr.prototype.mixins || {};
                } else {
                    parts = [];
                    superMixins = {};
                }

                proto = cls.prototype;
                mixins = proto.mixins; // since we are a mixin, there will be at least us
                for (name in mixins) {
                    if (mixins.hasOwnProperty(name) && !superMixins.hasOwnProperty(name)) {
                        mixin = mixins[name].self;
                        parts.push(mixin.$childEls || me.getClassChildEls(mixin));
                    }
                }

                parts.push(proto.hasOwnProperty('childEls') && proto.childEls);

                for (i = 0, length = parts.length; i < length; ++i) {
                    childEls = parts[i];
                    if (childEls && childEls.length) {
                        if (!result) {
                            result = childEls;
                        } else {
                            if (!forked) {
                                forked = true;
                                result = result.slice(0);
                            }
                            result.push.apply(result, childEls);
                        }
                    }
                }

                cls.$childEls = result = (result ? me.prune(result, !forked) : []);
            }

            return result;
        },

        prune: function (childEls, shared) {
            var index = childEls.length,
                map = {},
                name;

            while (index--) {
                name = childEls[index];
                if (typeof name != 'string') {
                    name = name.name;
                }

                if (!map[name]) {
                    map[name] = 1;
                } else {
                    if (shared) {
                        shared = false;
                        childEls = childEls.slice(0);
                    }
                    Ext.Array.erase(childEls, index, 1);
                }
            }

            return childEls;
        },

        /**
         * Removes items in the childEls array based on the return value of a supplied test
         * function. The function is called with a entry in childEls and if the test function
         * return true, that entry is removed. If false, that entry is kept.
         *
         * @param {Function} testFn The test function.
         */
        removeChildEls: function (testFn) {
            var me = this,
                old = me.getChildEls(),
                keepers = (me.childEls = []),
                n, i, cel;

            for (i = 0, n = old.length; i < n; ++i) {
                cel = old[i];
                if (!testFn(cel)) {
                    keepers.push(cel);
                }
            }
        }
    });