Show:
                            /**
                             * The Menu Component
                             *
                             * @module aui-menu
                             */
                            
                            var CSS_DROPDOWN_MENU = A.getClassName('dropdown', 'menu'),
                                CSS_MENU_INLINE = A.getClassName('menu', 'inline'),
                                CSS_MENU_ITEM = A.getClassName('menu', 'item'),
                            
                                EVENT_ITEM_SELECTED = 'itemSelected',
                            
                                LAYOUT_INLINE = 'inline',
                                LAYOUT_OVERLAY = 'overlay',
                            
                                MENU_ITEMS_SELECTOR = '> .' + CSS_DROPDOWN_MENU + ' > .' + CSS_MENU_ITEM,
                            
                                MIN_OVERLAY_VIEWPORT_WIDTH = 768;
                            
                            /**
                             * Fired when one of the menu's items is clicked.
                             *
                             * @event itemSelected
                             * @preventable _defItemSelected
                             */
                            
                            /**
                             * A base class for Menu.
                             *
                             * @class A.Menu
                             * @extends A.Dropdown
                             * @uses A.WidgetPosition, A.WidgetPositionAlign, A.WidgetPositionConstrain,
                             *     A.WidgetStack
                             * @param {Object} config Object literal specifying widget configuration
                             *     properties.
                             * @constructor
                             */
                            
                            A.Menu = A.Base.create('menu', A.Dropdown, [
                                A.WidgetPosition,
                                A.WidgetPositionAlign,
                                A.WidgetPositionConstrain,
                                A.WidgetStack
                            ], {
                            
                                /**
                                 * Constructor implementation. Lifecycle.
                                 *
                                 * @method initializer
                                 * @protected
                                 */
                                initializer: function() {
                                    this._eventHandles = [
                                        this.after({
                                            itemsChange: this._afterItemsChange,
                                            layoutModeChange: this._afterLayoutModeChange,
                                            'menu-item:shortcut': this._afterShorcut,
                                            'menu-item:submenuItemSelected': this._afterSubmenuItemSelected,
                                            openChange: this._afterMenuOpenChange
                                        }),
                                        A.on(this._onUISetXY, this, '_uiSetXY'),
                                        this.get('contentBox').delegate('click', this._onClickItem, MENU_ITEMS_SELECTOR, this),
                                        this.get('contentBox').delegate('key', A.bind(this._onKeyPressItem, this), 'press:13', MENU_ITEMS_SELECTOR),
                                        this.get('contentBox').delegate('mouseenter', this._onMouseEnterItem, MENU_ITEMS_SELECTOR, this),
                                        A.after('windowresize', A.bind(this._afterWindowResize, this))
                                    ];
                            
                                    this.publish({
                                        itemSelected: {
                                            defaultFn: this._defItemSelected
                                        }
                                    });
                            
                                    this._showItemSubmenuDebounce = A.debounce(
                                        this._showItemSubmenu,
                                        A.Menu.HIDE_SUBMENU_DELAY,
                                        this
                                    );
                                },
                            
                                /**
                                 * Destructor implementation. Lifecycle.
                                 *
                                 * @method destructor
                                 * @protected
                                 */
                                destructor: function() {
                                    var items = this.get('items');
                            
                                    for (var i = 0; i < items.length; i++) {
                                        items[i].destroy();
                                    }
                            
                                    (new A.EventHandle(this._eventHandles)).detach();
                                },
                            
                                /**
                                 * Syncs the UI. Lifecycle.
                                 *
                                 * @method syncUI
                                 * @protected
                                 */
                                syncUI: function() {
                                    this._updateLayoutMode();
                                },
                            
                                /**
                                 * Adds a menu item in the requested position.
                                 *
                                 * @method addItem
                                 * @param {Object} item The item to be added.
                                 * @param {Number} index The index to add the item to. If none is given,
                                 *  the item will be added to the end of the menu.
                                 */
                                addItem: function(item, index) {
                                    var items = this.get('items').concat();
                            
                                    if (index === undefined) {
                                        items.push(item);
                                    }
                                    else {
                                        items.splice(index, 0, item);
                                    }
                            
                                    this.set('items', items);
                                },
                            
                                /**
                                 * Returns the `A.MenuItem` instance for the given node.
                                 *
                                 * @method _getMenuItemFromNode
                                 * @param {Node} itemNode
                                 * @return {Node}
                                 */
                                getMenuItemFromNode: function(itemNode) {
                                    return itemNode.getData('menu-item');
                                },
                            
                                /**
                                 * Hides all the currently open submenus.
                                 *
                                 * @method hideAllSubmenus
                                 */
                                hideAllSubmenus: function() {
                                    var items = this.get('items');
                            
                                    for (var i = 0; i < items.length; i++) {
                                        this._hideItemSubmenu(items[i]);
                                    }
                                },
                            
                                /**
                                 * Removes the menu item from the menu.
                                 *
                                 * @method removeItem
                                 * @param {A.MenuItem} item The item to be removed.
                                 */
                                removeItem: function(item) {
                                    var index,
                                        items = this.get('items');
                            
                                    index = A.Array.indexOf(items, item);
                                    this.removeItemAtIndex(index);
                                },
                            
                                /**
                                 * Removes the menu item at the requested index.
                                 *
                                 * @method removeItemAtIndex
                                 * @param {Number} index The index of the item to be removed.
                                 */
                                removeItemAtIndex: function(index) {
                                    var items = this.get('items');
                            
                                    if (index >= 0 && index < items.length) {
                                        items.splice(index, 1);
                                        this.set('items', items);
                                    }
                                },
                            
                                /**
                                 * Fired after the `items` attribute changes.
                                 *
                                 * @method _afterItemsChange
                                 * @param {EventFacade} event
                                 * @protected
                                 */
                                _afterItemsChange: function(event) {
                                    for (var i = 0; i < event.prevVal.length; i++) {
                                        event.prevVal[i].removeTarget(this);
                                    }
                            
                                    this._uiSetItems(this.get('items'));
                                },
                            
                                /**
                                 * Fired after the `layoutMode` attribute changes.
                                 *
                                 * @method _afterLayoutModeChange
                                 * @protected
                                 */
                                _afterLayoutModeChange: function() {
                                    var layoutMode = this.get('layoutMode');
                            
                                    this.get('boundingBox').toggleClass(CSS_MENU_INLINE, layoutMode === LAYOUT_INLINE);
                            
                                    if (this.get('layoutMode') === LAYOUT_OVERLAY) {
                                        this.close();
                                    }
                                },
                            
                                /**
                                 * Fired after the `open` attribute is changed.
                                 *
                                 * @method _afterMenuOpenChange
                                 * @protected
                                 */
                                _afterMenuOpenChange: function() {
                                    if (this.get('open')) {
                                        if (!this._openedFirstTime) {
                                            this._uiSetItems(this.get('items'));
                                            this._openedFirstTime = true;
                                        }
                                    }
                                    else {
                                        this.hideAllSubmenus();
                                    }
                                },
                            
                                /**
                                 * Fired after the `shortcut` event is triggered.
                                 *
                                 * @method _afterShorcut
                                 * @param {EventFacade} event
                                 * @protected
                                 */
                                _afterShorcut: function(event) {
                                    this._selectItem(event.target, event.type);
                                },
                            
                                /**
                                 * Fired after the `submenuItemSelected` event is triggered.
                                 *
                                 * @method _afterSubmenuItemSelected
                                 * @param {EventFacade} event
                                 * @protected
                                 */
                                _afterSubmenuItemSelected: function(event) {
                                    this._selectItem(event.item, event.src);
                                },
                            
                                /**
                                 * Fired after the `windowresize` event.
                                 *
                                 * @method _afterWindowResize
                                 * @protected
                                 */
                                _afterWindowResize: function() {
                                    this._updateLayoutMode();
                                },
                            
                                /**
                                 * Default behavior for the `itemSelected` event.
                                 *
                                 * @method _defItemSelected
                                 * @protected
                                 */
                                _defItemSelected: function() {
                                    if (this.get('layoutMode') === LAYOUT_OVERLAY) {
                                        this.close();
                                    }
                                },
                            
                                /**
                                 * Hides the submenu for the given menu item, if there is one.
                                 *
                                 * @method _hideItemSubmenu
                                 * @param {MenuItem} item
                                 * @protected
                                 */
                                _hideItemSubmenu: function(item) {
                                    item.hideSubmenu();
                                    this._openSubmenuItem = null;
                                },
                            
                                /**
                                 * Fired when a menu item is clicked.
                                 *
                                 * @method _onClickItem
                                 * @param {EventFacade} event
                                 * @protected
                                 */
                                _onClickItem: function(event) {
                                    var item = this.getMenuItemFromNode(event.currentTarget);
                            
                                    if (this.get('layoutMode') === LAYOUT_INLINE) {
                                        if (item.isSubmenuOpen()) {
                                            this._hideItemSubmenu(item);
                                        }
                                        else {
                                            this._showItemSubmenu(item);
                                        }
                                    }
                            
                                    this._selectItem(item, event.type);
                            
                                    event.stopPropagation();
                                },
                            
                                /**
                                 * Fired when bounding box is key pressed.
                                 *
                                 * @method _onKeyPressItem
                                 * @param {EventFacade} event
                                 * @protected
                                 */
                                _onKeyPressItem: function(event) {
                                    this._onClickItem(event);
                                },
                            
                                /**
                                 * Fired when the mouse enters a menu item.
                                 *
                                 * @method _onMouseEnterItem
                                 * @param {EventFacade} event
                                 * @protected
                                 */
                                _onMouseEnterItem: function(event) {
                                    var item = this.getMenuItemFromNode(event.currentTarget);
                            
                                    if (this.get('layoutMode') === LAYOUT_OVERLAY) {
                                        this._showItemSubmenuDebounce(item);
                                    }
                                },
                            
                                /**
                                 * Fired before the `_uiSetXY` method runs.
                                 *
                                 * @method _onUISetXY
                                 * @protected
                                 */
                                _onUISetXY: function() {
                                    if (this.get('layoutMode') === LAYOUT_INLINE) {
                                        // Prevent setting `xy` on inline mode, as we want static positioning
                                        // in that case.
                                        return new A.Do.Prevent();
                                    }
                                },
                            
                                /**
                                 * Fires the `itemSelected` event for the given item, unless it's not selectable.
                                 *
                                 * @method _selectItem
                                 * @param {A.MenuItem} item
                                 * @protected
                                 */
                                _selectItem: function(item, src) {
                                    if (item.isSelectable()) {
                                        this.fire(EVENT_ITEM_SELECTED, {
                                            item: item,
                                            src: src
                                        });
                                    }
                                },
                            
                                /**
                                 * Sets the `items` attribute.
                                 *
                                 * @method _setItems
                                 * @param {Array} val
                                 * @protected
                                 */
                                _setItems: function(val) {
                                    var items = [];
                                    var i;
                            
                                    if (A.instanceOf(val, A.NodeList)) {
                                        val.each(function() {
                                            items.push(A.MenuItem.createFromNode(this));
                                        });
                                    }
                                    else {
                                        for (i = 0; i < val.length; i++) {
                                            if (!A.instanceOf(val[i], A.MenuItem)) {
                                                items.push(new A.MenuItem(val[i]));
                                            }
                                            else {
                                                items.push(val[i]);
                                            }
                                        }
                                    }
                            
                                    for (i = 0; i < items.length; i++) {
                                        items[i].addTarget(this);
                                    }
                            
                                    return items;
                                },
                            
                                /**
                                 * Shows the submenu for the given menu item, if there is one.
                                 *
                                 * @method _showItemSubmenu
                                 * @param {MenuItem} item
                                 * @protected
                                 */
                                _showItemSubmenu: function(item) {
                                    if (this._openSubmenuItem) {
                                        this._hideItemSubmenu(this._openSubmenuItem);
                                    }
                            
                                    item.showSubmenu(this.get('layoutMode') === LAYOUT_OVERLAY, this.get('zIndex') + 1);
                                    this._openSubmenuItem = item;
                                },
                            
                                /**
                                 * Updates the UI according to the value of the `items` attribute.
                                 *
                                 * @method _uiSetItems
                                 * @param {Array} items
                                 * @protected
                                 */
                                _uiSetItems: function(items) {
                                    var dropdownMenu = this.get('contentBox').one('.' + CSS_DROPDOWN_MENU);
                            
                                    dropdownMenu.empty();
                                    for (var i = 0; i < items.length; i++) {
                                        dropdownMenu.append(items[i].get('node'));
                                    }
                                },
                            
                                /**
                                 * Updates the layout mode according to the size of the viewport.
                                 *
                                 * @method _updateLayoutMode
                                 * @protected
                                 */
                                _updateLayoutMode: function() {
                                    if (A.DOM.viewportRegion().width < MIN_OVERLAY_VIEWPORT_WIDTH) {
                                        this._set('layoutMode', LAYOUT_INLINE);
                                    }
                                    else {
                                        this._set('layoutMode', LAYOUT_OVERLAY);
                                    }
                                }
                            }, {
                                /**
                                 * Static property used to define the default attribute configuration.
                                 *
                                 * @property ATTRS
                                 * @type Object
                                 * @static
                                 */
                                ATTRS: {
                                    /**
                                     * Information about the items that should be inside the menu.
                                     *
                                     * @attribute items
                                     * @type Array
                                     */
                                    items: {
                                        lazyAdd: false,
                                        setter: '_setItems',
                                        validator: function(val) {
                                            return A.Lang.isArray(val) || A.instanceOf(val, A.NodeList);
                                        },
                                        value: []
                                    },
                            
                                    /**
                                     * The layout mode of the menu. Can be either overlay (default) or
                                     * inline.
                                     *
                                     * @attribute layoutMode
                                     * @type String
                                     */
                                    layoutMode: {
                                        readOnly: true,
                                        validator: A.Lang.isString,
                                        value: LAYOUT_OVERLAY
                                    }
                                },
                            
                                /**
                                 * Static property provides a string to identify the CSS prefix.
                                 *
                                 * @property CSS_PREFIX
                                 * @type String
                                 * @static
                                 */
                                CSS_PREFIX: A.getClassName('menu'),
                            
                                /**
                                 * Static property provides the delay value (in ms) for hiding submenus.
                                 *
                                 * @property HIDE_SUBMENU_DELAY
                                 * @type Number
                                 * @static
                                 */
                                HIDE_SUBMENU_DELAY: 200,
                            
                                /**
                                 * Object hash, defining how attribute values have to be parsed from markup.
                                 *
                                 * @property HTML_PARSER
                                 * @type Object
                                 * @static
                                 */
                                HTML_PARSER: {
                                    items: [MENU_ITEMS_SELECTOR]
                                }
                            });