text: define([
  	"dojo/_base/declare", // declare
  	"dojo/dom", // dom.isDescendant domClass.replace
  	"dojo/dom-attr",
  	"dojo/dom-class", // domClass.replace
  	"dojo/_base/lang", // lang.hitch
  	"dojo/mouse", // mouse.enter, mouse.leave
  	"dojo/on",
  	"dojo/window",
  	"../a11yclick",
  	"../registry",
  	"../Widget",
  	"../Container",
  	"../CssState",
  	"../KeyNav",
  	"../_TemplatedMixin"
  ], function(declare, dom, domAttr, domClass, lang, mouse, on, winUtils, a11yclick,
  			registry, Widget, Container, _CssStateMixin, _KeyNavMixin, _TemplatedMixin){
  
  	// module:
  	//		dui/_MenuBase
  
  	return declare("dui._MenuBase", [Widget, _TemplatedMixin, Container, KeyNav, CssState], {
  		// summary:
  		//		Abstract base class for Menu and MenuBar.
  		//		Subclass should implement _onUpArrow(), _onDownArrow(), _onLeftArrow(), and _onRightArrow().
  
  		// selected: dui/MenuItem
  		//		Currently selected (a.k.a. highlighted) MenuItem, or null if no MenuItem is selected.
  		//		If a submenu is open, will be set to MenuItem that displayed the submenu.   OTOH, if
  		//		this Menu is in passive mode (i.e. hasn't been clicked yet), will be null, because
  		//		"selected" is not merely "hovered".
  		selected: null,
  		_setSelectedAttr: function(item){
  			if(this.selected != item){
  				if(this.selected){
  					this.selected._setSelected(false);
  					this._onChildDeselect(this.selected);
  				}
  				if(item){
  					item._setSelected(true);
  				}
  				this._set("selected", item);
  			}
  		},
  
  		// activated: [readonly] Boolean
  		//		This Menu has been clicked (mouse or via space/arrow key) or opened as a submenu,
  		//		so mere mouseover will open submenus.  Focusing a menu via TAB does NOT automatically make it active
  		//		since TAB is a navigation operation and not a selection one.
  		//		For Windows apps, pressing the ALT key focuses the menubar menus (similar to TAB navigation) but the
  		//		menu is not active (ie no dropdown) until an item is clicked.
  		activated: false,
  		_setActivatedAttr: function(val){
  			domClass.toggle(this.domNode, "duiMenuActive", val);
  			domClass.toggle(this.domNode, "duiMenuPassive", !val);
  			this._set("activated", val);
  		},
  
  		// parentMenu: [readonly] Widget
  		//		pointer to menu that displayed me
  		parentMenu: null,
  
  		// popupDelay: Integer
  		//		After a menu has been activated (by clicking on it etc.), number of milliseconds before hovering
  		//		(without clicking) another MenuItem causes that MenuItem's popup to automatically open.
  		popupDelay: 500,
  
  		// passivePopupDelay: Integer
  		//		For a passive (unclicked) Menu, number of milliseconds before hovering (without clicking) will cause
  		//		the popup to open.  Default is Infinity, meaning you need to click the menu to open it.
  		passivePopupDelay: Infinity,
  
  		// focusOnOpen: Boolean
  		//		A toggle to control whether or not a Menu gets focused when opened as a drop down from a MenuBar
  		//		or DropDownButton/ComboButton.   Note though that it always get focused when opened via the keyboard.
  		focusOnOpen: false,
  
  		childSelector: function(/*DOMNode*/ node){
  			// summary:
  			//		Selector (passed to on.selector()) used to identify MenuItem child widgets, but exclude inert children
  			//		like MenuSeparator.  If subclass overrides to a string (ex: "> *"), the subclass must require dojo/query.
  			// tags:
  			//		protected
  
  			var widget = registry.byNode(node);
  			return node.parentNode == this.containerNode && widget && widget.focus;
  		},
  
  		postCreate: function(){
  			var self = this,
  				matches = typeof this.childSelector == "string" ? this.childSelector : lang.hitch(this, "childSelector");
  			this.own(
  				on(this.containerNode, on.selector(matches, mouse.enter), function(){
  					self.onItemHover(registry.byNode(this));
  				}),
  				on(this.containerNode, on.selector(matches, mouse.leave), function(){
  					self.onItemUnhover(registry.byNode(this));
  				}),
  				on(this.containerNode, on.selector(matches, a11yclick), function(evt){
  					self.onItemClick(registry.byNode(this), evt);
  					evt.stopPropagation();
  				}),
  				on(this.containerNode, on.selector(matches, "focusin"), function(){
  					self._onItemFocus(registry.byNode(this));
  				})
  			);
  			this.inherited(arguments);
  		},
  
  		onKeyboardSearch: function(/*MenuItem*/ item, /*Event*/ evt, /*String*/ searchString, /*Number*/ numMatches){
  			// summary:
  			//		Attach point for notification about when a menu item has been searched for
  			//		via the keyboard search mechanism.
  			// tags:
  			//		protected
  			this.inherited(arguments);
  			if(!!item && (numMatches == -1 || (!!item.popup && numMatches == 1))){
  				this.onItemClick(item, evt);
  			}
  		},
  
  		_keyboardSearchCompare: function(/*dui/Widget*/ item, /*String*/ searchString){
  			// summary:
  			//		Compares the searchString to the widget's text label, returning:
  			//		-1: a high priority match and stop searching
  			//		 0: no match
  			//		 1: a match but keep looking for a higher priority match
  			// tags:
  			//		private
  			if(!!item.shortcutKey){
  				// accessKey matches have priority
  				return searchString == item.shortcutKey.toLowerCase() ? -1 : 0;
  			}
  			return this.inherited(arguments) ? 1 : 0; // change return value of -1 to 1 so that searching continues
  		},
  
  		onExecute: function(){
  			// summary:
  			//		Attach point for notification about when a menu item has been executed.
  			//		This is an internal mechanism used for Menus to signal to their parent to
  			//		close them, because they are about to execute the onClick handler.  In
  			//		general developers should not attach to or override this method.
  			// tags:
  			//		protected
  		},
  
  		onCancel: function(/*Boolean*/ /*===== closeAll =====*/){
  			// summary:
  			//		Attach point for notification about when the user cancels the current menu
  			//		This is an internal mechanism used for Menus to signal to their parent to
  			//		close them.  In general developers should not attach to or override this method.
  			// tags:
  			//		protected
  		},
  
  		_moveToPopup: function(/*Event*/ evt){
  			// summary:
  			//		This handles the right arrow key (left arrow key on RTL systems),
  			//		which will either open a submenu, or move to the next item in the
  			//		ancestor MenuBar
  			// tags:
  			//		private
  
  			if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
  				this.onItemClick(this.focusedChild, evt);
  			}else{
  				var topMenu = this._getTopMenu();
  				if(topMenu && topMenu._isMenuBar){
  					topMenu.focusNext();
  				}
  			}
  		},
  
  		_onPopupHover: function(/*Event*/ /*===== evt =====*/){
  			// summary:
  			//		This handler is called when the mouse moves over the popup.
  			// tags:
  			//		private
  
  			// if the mouse hovers over a menu popup that is in pending-close state,
  			// then stop the close operation.
  			// This can't be done in onItemHover since some popup targets don't have MenuItems (e.g. ColorPicker)
  
  			// highlight the parent menu item pointing to this popup (in case user temporarily moused over another MenuItem)
  			this.set("selected", this.currentPopupItem);
  
  			// cancel the pending close (if there is one) (in case user temporarily moused over another MenuItem)
  			this._stopPendingCloseTimer();
  		},
  
  		onItemHover: function(/*MenuItem*/ item){
  			// summary:
  			//		Called when cursor is over a MenuItem.
  			// tags:
  			//		protected
  
  			// Don't do anything unless user has "activated" the menu by:
  			//		1) clicking it
  			//		2) opening it from a parent menu (which automatically activates it)
  
  			if(this.activated){
  				this.set("selected", item);
  				if(item.popup && !item.disabled && !this.hover_timer){
  					this.hover_timer = this.defer(function(){
  						this._openItemPopup(item);
  					}, this.popupDelay);
  				}
  			}else if(this.passivePopupDelay < Infinity){
  				if(this.passive_hover_timer){
  					this.passive_hover_timer.remove();
  				}
  				this.passive_hover_timer = this.defer(function(){
  					this.onItemClick(item, {type: "click"});
  				}, this.passivePopupDelay);
  			}
  
  			this._hoveredChild = item;
  		},
  
  		_onChildDeselect: function(item){
  			// summary:
  			//		Called when a child MenuItem becomes deselected.   Setup timer to close its popup.
  
  			this._stopPopupTimer();
  
  			// Setup timer to close all popups that are open and descendants of this menu.
  			// Will be canceled if user quickly moves the mouse over the popup.
  			if(this.currentPopupItem == item){
  				this._stopPendingCloseTimer();
  				this._pendingClose_timer = this.defer(function(){
  					this._pendingClose_timer = null;
  					this.currentPopupItem = null;
  					item._closePopup(); // this calls onClose
  				}, this.popupDelay);
  			}
  		},
  
  		onItemUnhover: function(/*MenuItem*/ item){
  			// summary:
  			//		Callback fires when mouse exits a MenuItem
  			// tags:
  			//		protected
  
  			if(this._hoveredChild == item){
  				this._hoveredChild = null;
  			}
  
  			if(this.passive_hover_timer){
  				this.passive_hover_timer.remove();
  				this.passive_hover_timer = null;
  			}
  		},
  
  		_stopPopupTimer: function(){
  			// summary:
  			//		Cancels the popup timer because the user has stop hovering
  			//		on the MenuItem, etc.
  			// tags:
  			//		private
  
  			if(this.hover_timer){
  				this.hover_timer = this.hover_timer.remove();
  			}
  		},
  
  		_stopPendingCloseTimer: function(){
  			// summary:
  			//		Cancels the pending-close timer because the close has been preempted
  			// tags:
  			//		private
  			if(this._pendingClose_timer){
  				this._pendingClose_timer = this._pendingClose_timer.remove();
  			}
  		},
  
  		_getTopMenu: function(){
  			// summary:
  			//		Returns the top menu in this chain of Menus
  			// tags:
  			//		private
  			for(var top = this; top.parentMenu; top = top.parentMenu){}
  			return top;
  		},
  
  		onItemClick: function(/*dui/Widget*/ item, /*Event*/ evt){
  			// summary:
  			//		Handle clicks on an item.
  			// tags:
  			//		private
  
  			if(this.passive_hover_timer){
  				this.passive_hover_timer.remove();
  			}
  
  			this.focusChild(item);
  
  			if(item.disabled){
  				return false;
  			}
  
  			if(item.popup){
  				this.set("selected", item);
  				this.set("activated", true);
  				var byKeyboard = /^key/.test(evt._origType || evt.type) ||
  					(evt.clientX == 0 && evt.clientY == 0);	// detects accessKey like ALT+SHIFT+F, where type is "click"
  				this._openItemPopup(item, byKeyboard);
  			}else{
  				// before calling user defined handler, close hierarchy of menus
  				// and restore focus to place it was when menu was opened
  				this.onExecute();
  
  				// user defined handler for click
  				item._onClick ? item._onClick(evt) : item.onClick(evt);
  			}
  		},
  
  		_openItemPopup: function(/*dui/MenuItem*/ from_item, /*Boolean*/ focus){
  			// summary:
  			//		Open the popup to the side of/underneath the current menu item, and optionally focus first item
  			// tags:
  			//		protected
  
  			if(from_item == this.currentPopupItem){
  				// Specified popup is already being shown, so just return
  				return;
  			}
  			if(this.currentPopupItem){
  				// If another popup is currently shown, then close it
  				this._stopPendingCloseTimer();
  				this.currentPopupItem._closePopup();
  			}
  			this._stopPopupTimer();
  
  			var popup = from_item.popup;
  			popup.parentMenu = this;
  
  			// detect mouseover of the popup to handle lazy mouse movements that temporarily focus other menu items\c
  			this.own(this._mouseoverHandle = on.once(popup.domNode, "mouseover", lang.hitch(this, "_onPopupHover")));
  
  			var self = this;
  			from_item._openPopup({
  				parent: this,
  				orient: this._orient || ["after", "before"],
  				onCancel: function(){ // called when the child menu is canceled
  					if(focus){
  						// put focus back on my node before focused node is hidden
  						self.focusChild(from_item);
  					}
  
  					// close the submenu (be sure this is done _after_ focus is moved)
  					self._cleanUp();
  				},
  				onExecute: lang.hitch(this, "_cleanUp", true),
  				onClose: function(){
  					// Remove handler created by onItemHover
  					if(self._mouseoverHandle){
  						self._mouseoverHandle.remove();
  						delete self._mouseoverHandle;
  					}
  				}
  			}, focus);
  
  			this.currentPopupItem = from_item;
  
  			// TODO: focusing a popup should clear tabIndex on Menu (and it's child MenuItems), so that neither
  			// TAB nor SHIFT-TAB returns to the menu.  Only ESC or ENTER should return to the menu.
  		},
  
  		onOpen: function(/*Event*/ /*===== e =====*/){
  			// summary:
  			//		Callback when this menu is opened.
  			//		This is called by the popup manager as notification that the menu
  			//		was opened.
  			// tags:
  			//		private
  
  			this.isShowingNow = true;
  			this.set("activated", true);
  		},
  
  		onClose: function(){
  			// summary:
  			//		Callback when this menu is closed.
  			//		This is called by the popup manager as notification that the menu
  			//		was closed.
  			// tags:
  			//		private
  
  			this.set("activated", false);
  			this.set("selected", null);
  			this.isShowingNow = false;
  			this.parentMenu = null;
  		},
  
  		_closeChild: function(){
  			// summary:
  			//		Called when submenu is clicked or focus is lost.  Close hierarchy of menus.
  			// tags:
  			//		private
  			this._stopPopupTimer();
  
  			if(this.currentPopupItem){
  				// If focus is on a descendant MenuItem then move focus to me,
  				// because IE doesn't like it when you display:none a node with focus,
  				// and also so keyboard users don't lose control.
  				// Likely, immediately after a user defined onClick handler will move focus somewhere
  				// else, like a Dialog.
  				if(this.focused){
  					domAttr.set(this.selected.focusNode, "tabIndex", this.tabIndex);
  					this.selected.focusNode.focus();
  				}
  
  				// Close all popups that are open and descendants of this menu
  				this.currentPopupItem._closePopup();
  				this.currentPopupItem = null;
  			}
  		},
  
  		_onItemFocus: function(/*MenuItem*/ item){
  			// summary:
  			//		Called when child of this Menu gets focus from:
  			//
  			//		1. clicking it
  			//		2. tabbing into it
  			//		3. being opened by a parent menu.
  			//
  			//		This is not called just from mouse hover.
  
  			if(this._hoveredChild && this._hoveredChild != item){
  				this.onItemUnhover(this._hoveredChild);	// any previous mouse movement is trumped by focus selection
  			}
  			this.set("selected", item);
  		},
  
  		_onBlur: function(){
  			// summary:
  			//		Called when focus is moved away from this Menu and it's submenus.
  			// tags:
  			//		protected
  
  			this._cleanUp(true);
  			this.inherited(arguments);
  		},
  
  		_cleanUp: function(/*Boolean*/ clearSelectedItem){
  			// summary:
  			//		Called when the user is done with this menu.  Closes hierarchy of menus.
  			// tags:
  			//		private
  
  			this._closeChild(); // don't call this.onClose since that's incorrect for MenuBar's that never close
  			if(typeof this.isShowingNow == 'undefined'){ // non-popup menu doesn't call onClose
  				this.set("activated", false);
  			}
  
  			if(clearSelectedItem){
  				this.set("selected", null);
  			}
  		}
  	});
  });
  