    /**
     * @author Ed Spencer
     * TabBar is used internally by a {@link Ext.tab.Panel TabPanel} and typically should not need to be created manually.
     * The tab bar automatically removes the default title provided by {@link Ext.panel.Header}
     */
    Ext.define('Ext.tab.Bar', {
        extend: 'Ext.panel.Header',
        alias: 'widget.tabbar',
        baseCls: Ext.baseCSSPrefix + 'tab-bar',

        requires: [
            'Ext.tab.Tab',
            'Ext.FocusManager'
        ],

        isTabBar: true,

        /**
         * @cfg {String} title @hide
         */

        /**
         * @cfg {String} iconCls @hide
         */

        // @private
        defaultType: 'tab',

        /**
         * @cfg {Boolean} plain
         * True to not show the full background on the tabbar
         */
        plain: false,

        // @private
        renderTpl: [
            '<div id="{id}-body" class="{baseCls}-body <tpl if="bodyCls"> {bodyCls}</tpl> <tpl if="ui"> {baseCls}-body-{ui}<tpl for="uiCls"> {parent.baseCls}-body-{parent.ui}-{.}</tpl></tpl>"<tpl if="bodyStyle"> style="{bodyStyle}"</tpl>></div>',
            '<div id="{id}-strip" class="{baseCls}-strip<tpl if="ui"> {baseCls}-strip-{ui}<tpl for="uiCls"> {parent.baseCls}-strip-{parent.ui}-{.}</tpl></tpl>"></div>'
        ],

        /**
         * @cfg {Number} minTabWidth
         * The minimum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#minTabWidth minTabWidth} value.
         * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#minTabWidth minTabWidth} config on the TabPanel.
         */

        /**
         * @cfg {Number} maxTabWidth
         * The maximum width for a tab in this tab Bar. Defaults to the tab Panel's {@link Ext.tab.Panel#maxTabWidth maxTabWidth} value.
         * @deprecated This config is deprecated. It is much easier to use the {@link Ext.tab.Panel#maxTabWidth maxTabWidth} config on the TabPanel.
         */

        // @private
        initComponent: function() {
            var me = this,
                keys;

            if (me.plain) {
                me.setUI(me.ui + '-plain');
            }

            me.addClsWithUI(me.dock);

            me.addEvents(
                /**
                 * @event change
                 * Fired when the currently-active tab has changed
                 * @param {Ext.tab.Bar} tabBar The TabBar
                 * @param {Ext.tab.Tab} tab The new Tab
                 * @param {Ext.Component} card The card that was just shown in the TabPanel
                 */
                'change'
            );

            me.addChildEls('body', 'strip');
            me.callParent(arguments);

            // TabBar must override the Header's align setting.
            me.layout.align = (me.orientation == 'vertical') ? 'left' : 'top';
            me.layout.overflowHandler = Ext.create('Ext.layout.container.boxOverflow.Scroller', me.layout);

            me.remove(me.titleCmp);
            delete me.titleCmp;

            // Subscribe to Ext.FocusManager for key navigation
            keys = me.orientation == 'vertical' ? ['up', 'down'] : ['left', 'right'];
            Ext.FocusManager.subscribe(me, {
                keys: keys
            });

            Ext.apply(me.renderData, {
                bodyCls: me.bodyCls
            });
        },

        // @private
        onAdd: function(tab) {
            tab.position = this.dock;
            this.callParent(arguments);
        },

        onRemove: function(tab) {
            var me = this;

            if (tab === me.previousTab) {
                me.previousTab = null;
            }
            if (me.items.getCount() === 0) {
                me.activeTab = null;
            }
            me.callParent(arguments);
        },

        // @private
        afterRender: function() {
            var me = this;

            me.mon(me.el, {
                scope: me,
                click: me.onClick,
                delegate: '.' + Ext.baseCSSPrefix + 'tab'
            });
            me.callParent(arguments);

        },

        afterComponentLayout : function() {
            var me = this;

            me.callParent(arguments);
            me.strip.setWidth(me.el.getWidth());
        },

        // @private
        onClick: function(e, target) {
            // The target might not be a valid tab el.
            var tab = Ext.getCmp(target.id),
                tabPanel = this.tabPanel;

            target = e.getTarget();

            if (tab && tab.isDisabled && !tab.isDisabled()) {
                if (tab.closable && target === tab.closeEl.dom) {
                    tab.onCloseClick();
                } else {
                    if (tabPanel) {
                        // TabPanel will card setActiveTab of the TabBar
                        tabPanel.setActiveTab(tab.card);
                    } else {
                        this.setActiveTab(tab);
                    }
                    tab.focus();
                }
            }
        },

        /**
         * @private
         * Closes the given tab by removing it from the TabBar and removing the corresponding card from the TabPanel
         * @param {Ext.tab.Tab} tab The tab to close
         */
        closeTab: function(tab) {
            var me = this,
                card = tab.card,
                tabPanel = me.tabPanel,
                nextTab;

            if (card && card.fireEvent('beforeclose', card) === false) {
                return false;
            }

            if (tab.active && me.items.getCount() > 1) {
                nextTab = me.previousTab || tab.next('tab') || me.items.first();
                me.setActiveTab(nextTab);
                if (tabPanel) {
                    tabPanel.setActiveTab(nextTab.card);
                }
            }
            /*
             * force the close event to fire. By the time this function returns,
             * the tab is already destroyed and all listeners have been purged
             * so the tab can't fire itself.
             */
            tab.fireClose();
            me.remove(tab);

            if (tabPanel && card) {
                card.fireEvent('close', card);
                tabPanel.remove(card);
            }

            if (nextTab) {
                nextTab.focus();
            }
        },

        /**
         * @private
         * Marks the given tab as active
         * @param {Ext.tab.Tab} tab The tab to mark active
         */
        setActiveTab: function(tab) {
            if (tab.disabled) {
                return;
            }
            var me = this;
            if (me.activeTab) {
                me.previousTab = me.activeTab;
                me.activeTab.deactivate();
            }
            tab.activate();

            if (me.rendered) {
                me.layout.layout();
                tab.el && tab.el.scrollIntoView(me.layout.getRenderTarget());
            }
            me.activeTab = tab;
            me.fireEvent('change', me, tab, tab.card);
        }
    });