    /**
     * AbstractBox is a superclass for the two box layouts:
     *
     * * {@link Ext.layout.HBox hbox}
     * * {@link Ext.layout.VBox vbox}
     *
     * AbstractBox itself is never used directly, but its subclasses provide flexible arrangement of child components
     * inside a {@link Ext.Container Container}. For a full overview of layouts check out the
     * [Layout Guide](#!/guide/layouts).
     *
     * ## Horizontal Box
     *
     * HBox allows you to easily lay out child components horizontally. It can size items based on a fixed width or a
     * fraction of the total width available, enabling you to achieve flexible layouts that expand or contract to fill the
     * space available.
     *
     * {@img ../guides/layouts/hbox.jpg}
     *
     * See the {@link Ext.layout.HBox HBox layout docs} for more information on using hboxes.
     *
     * ## Vertical Box
     *
     * VBox allows you to easily lay out child components verticaly. It can size items based on a fixed height or a
     * fraction of the total height available, enabling you to achieve flexible layouts that expand or contract to fill the
     * space available.
     *
     * {@img ../guides/layouts/vbox.jpg}
     *
     * See the {@link Ext.layout.VBox VBox layout docs} for more information on using vboxes.
     */
    Ext.define('Ext.layout.AbstractBox', {
        extend: 'Ext.layout.Default',

        config: {
            /**
             * @cfg {String} align
             * Controls how the child items of the container are aligned. Acceptable configuration values for this property are:
             *
             * - **top** : **Default** child items are aligned vertically at the **top** of the container
             * - **middle** : child items are aligned vertically in the **middle** of the container
             * - **stretch** : child items are stretched vertically to fill the height of the container
             * - **stretchmax** : child items are stretched vertically to the height of the largest item.
             * @accessor
             */
            align: 'stretch',

            /**
             * @cfg {String} pack
             * Controls how the child items of the container are packed together. Acceptable configuration values
             * for this property are:
             *
             * - ** start ** : child items are packed together at left side of container
             * - ** center ** : child items are packed together at mid-width of container
             * - ** end ** : child items are packed together at right side of container
             * @accessor
             */
            pack: null
        },

        flexItemCls: Ext.baseCSSPrefix + 'layout-box-item',

        positionMap: {
            middle: 'center',
            left: 'start',
            top: 'start',
            right: 'end',
            bottom: 'end'
        },

        constructor: function(container) {
            this.callParent(arguments);

            this.wrappers = {};

            container.innerElement.addCls(this.cls);

            container.on(this.sizeChangeEventName, 'onItemSizeChange', this, {
                delegate: '> component'
            });
        },

        reapply: function() {
            this.container.innerElement.addCls(this.cls);

            this.updatePack(this.getPack());
            this.updateAlign(this.getAlign());
        },

        unapply: function() {
            this.container.innerElement.removeCls(this.cls);

            this.updatePack(null);
            this.updateAlign(null);
        },

        /**
         * @private
         */
        doItemAdd: function(item, index) {
            this.callParent(arguments);

            if (item.isInnerItem()) {
                var size = item.getConfig(this.sizePropertyName),
                    config = item.config;

                if (!size && ('flex' in config)) {
                    this.setItemFlex(item, config.flex);
                }
            }
        },

        /**
         * @private
         */
        doItemRemove: function(item) {
            if (item.isInnerItem()) {
                this.setItemFlex(item, null);
            }

            this.callParent(arguments);
        },

        onItemSizeChange: function(item) {
            this.setItemFlex(item, null);
        },

        /**
         * @private
         */
        doItemCenteredChange: function(item, centered) {
            if (centered) {
                this.setItemFlex(item, null);
            }

            this.callParent(arguments);
        },

        /**
         * @private
         */
        doItemFloatingChange: function(item, floating) {
            if (floating) {
                this.setItemFlex(item, null);
            }

            this.callParent(arguments);
        },

        /**
         * @private
         */
        doItemDockedChange: function(item, docked) {
            if (docked) {
                this.setItemFlex(item, null);
            }

            this.callParent(arguments);
        },

        redrawContainer: function() {
            var container = this.container,
                renderedTo = container.renderElement.dom.parentNode;

            if (renderedTo && renderedTo.nodeType !== 11) {
                container.innerElement.redraw();
            }
        },

        /**
         * Sets the flex of an item in this box layout.
         * @param {Ext.Component} item The item of this layout which you want to update the flex of.
         * @param {Number} flex The flex to set on this method
         */
        setItemFlex: function(item, flex) {
            var element = item.element,
                flexItemCls = this.flexItemCls;

            if (flex) {
                element.addCls(flexItemCls);
            }
            else if (element.hasCls(flexItemCls)) {
                this.redrawContainer();
                element.removeCls(flexItemCls);
            }

            element.dom.style.webkitBoxFlex = flex;
        },

        convertPosition: function(position) {
            if (this.positionMap.hasOwnProperty(position)) {
                return this.positionMap[position];
            }

            return position;
        },

        applyAlign: function(align) {
            return this.convertPosition(align);
        },

        updateAlign: function(align) {
            this.container.innerElement.dom.style.webkitBoxAlign = align;
        },

        applyPack: function(pack) {
             return this.convertPosition(pack);
        },

        updatePack: function(pack) {
            this.container.innerElement.dom.style.webkitBoxPack = pack;
        }
    });