text: define("dojo/parser", [
  	"require", "./_base/kernel", "./_base/lang", "./_base/array", "./_base/config", "./dom", "./_base/window",
  		"./_base/url", "./aspect", "./promise/all", "./date/stamp", "./Deferred", "./has", "./query", "./on", "./ready"
  ], function(require, dojo, dlang, darray, config, dom, dwindow, _Url, aspect, all, dates, Deferred, has, query, don, ready){
  
  	// module:
  	//		dojo/parser
  
  	new Date("X"); // workaround for #11279, new Date("") == NaN
  
  	// data-dojo-props etc. is not restricted to JSON, it can be any javascript
  	function myEval(text){
  		return eval("(" + text + ")");
  	}
  
  	// Widgets like BorderContainer add properties to _Widget via dojo.extend().
  	// If BorderContainer is loaded after _Widget's parameter list has been cached,
  	// we need to refresh that parameter list (for _Widget and all widgets that extend _Widget).
  	var extendCnt = 0;
  	aspect.after(dlang, "extend", function(){
  		extendCnt++;
  	}, true);
  
  	function getNameMap(ctor){
  		// summary:
  		//		Returns map from lowercase name to attribute name in class, ex: {onclick: "onClick"}
  		var map = ctor._nameCaseMap, proto = ctor.prototype;
  
  		// Create the map if it's undefined.
  		// Refresh the map if a superclass was possibly extended with new methods since the map was created.
  		if(!map || map._extendCnt < extendCnt){
  			map = ctor._nameCaseMap = {};
  			for(var name in proto){
  				if(name.charAt(0) === "_"){
  					continue;
  				}	// skip internal properties
  				map[name.toLowerCase()] = name;
  			}
  			map._extendCnt = extendCnt;
  		}
  		return map;
  	}
  
  	// Map from widget name or list of widget names(ex: "dijit/form/Button,acme/MyMixin") to a constructor.
  	var _ctorMap = {};
  
  	function getCtor(/*String[]*/ types, /*Function?*/ contextRequire){
  		// summary:
  		//		Retrieves a constructor.  If the types array contains more than one class/MID then the
  		//		subsequent classes will be mixed into the first class and a unique constructor will be
  		//		returned for that array.
  
  		var ts = types.join();
  		if(!_ctorMap[ts]){
  			var mixins = [];
  			for(var i = 0, l = types.length; i < l; i++){
  				var t = types[i];
  				// TODO: Consider swapping getObject and require in the future
  				mixins[mixins.length] = (_ctorMap[t] = _ctorMap[t] || (dlang.getObject(t) || (~t.indexOf('/') &&
  					(contextRequire ? contextRequire(t) : require(t)))));
  			}
  			var ctor = mixins.shift();
  			_ctorMap[ts] = mixins.length ? (ctor.createSubclass ? ctor.createSubclass(mixins) : ctor.extend.apply(ctor, mixins)) : ctor;
  		}
  
  		return _ctorMap[ts];
  	}
  
  	var parser = {
  		// summary:
  		//		The Dom/Widget parsing package
  
  		_clearCache: function(){
  			// summary:
  			//		Clear cached data.   Used mainly for benchmarking.
  			extendCnt++;
  			_ctorMap = {};
  		},
  
  		_functionFromScript: function(script, attrData){
  			// summary:
  			//		Convert a `<script type="dojo/method" args="a, b, c"> ... </script>`
  			//		into a function
  			// script: DOMNode
  			//		The `<script>` DOMNode
  			// attrData: String
  			//		For HTML5 compliance, searches for attrData + "args" (typically
  			//		"data-dojo-args") instead of "args"
  			var preamble = "",
  				suffix = "",
  				argsStr = (script.getAttribute(attrData + "args") || script.getAttribute("args")),
  				withStr = script.getAttribute("with");
  
  			// Convert any arguments supplied in script tag into an array to be passed to the
  			var fnArgs = (argsStr || "").split(/\s*,\s*/);
  
  			if(withStr && withStr.length){
  				darray.forEach(withStr.split(/\s*,\s*/), function(part){
  					preamble += "with(" + part + "){";
  					suffix += "}";
  				});
  			}
  
  			return new Function(fnArgs, preamble + script.innerHTML + suffix);
  		},
  
  		instantiate: function(nodes, mixin, options){
  			// summary:
  			//		Takes array of nodes, and turns them into class instances and
  			//		potentially calls a startup method to allow them to connect with
  			//		any children.
  			// nodes: Array
  			//		Array of DOM nodes
  			// mixin: Object?
  			//		An object that will be mixed in with each node in the array.
  			//		Values in the mixin will override values in the node, if they
  			//		exist.
  			// options: Object?
  			//		An object used to hold kwArgs for instantiation.
  			//		See parse.options argument for details.
  			// returns:
  			//		Array of instances.
  
  			mixin = mixin || {};
  			options = options || {};
  
  			var dojoType = (options.scope || dojo._scopeName) + "Type", // typically "dojoType"
  				attrData = "data-" + (options.scope || dojo._scopeName) + "-", // typically "data-dojo-"
  				dataDojoType = attrData + "type", // typically "data-dojo-type"
  				dataDojoMixins = attrData + "mixins";					// typically "data-dojo-mixins"
  
  			var list = [];
  			darray.forEach(nodes, function(node){
  				var type = dojoType in mixin ? mixin[dojoType] : node.getAttribute(dataDojoType) || node.getAttribute(dojoType);
  				if(type){
  					var mixinsValue = node.getAttribute(dataDojoMixins),
  						types = mixinsValue ? [type].concat(mixinsValue.split(/\s*,\s*/)) : [type];
  
  					list.push({
  						node: node,
  						types: types
  					});
  				}
  			});
  
  			// Instantiate the nodes and return the list of instances.
  			return this._instantiate(list, mixin, options);
  		},
  
  		_instantiate: function(nodes, mixin, options, returnPromise){
  			// summary:
  			//		Takes array of objects representing nodes, and turns them into class instances and
  			//		potentially calls a startup method to allow them to connect with
  			//		any children.
  			// nodes: Array
  			//		Array of objects like
  			//	|		{
  			//	|			ctor: Function (may be null)
  			//	|			types: ["dijit/form/Button", "acme/MyMixin"] (used if ctor not specified)
  			//	|			node: DOMNode,
  			//	|			scripts: [ ... ],	// array of <script type="dojo/..."> children of node
  			//	|			inherited: { ... }	// settings inherited from ancestors like dir, theme, etc.
  			//	|		}
  			// mixin: Object
  			//		An object that will be mixed in with each node in the array.
  			//		Values in the mixin will override values in the node, if they
  			//		exist.
  			// options: Object
  			//		An options object used to hold kwArgs for instantiation.
  			//		See parse.options argument for details.
  			// returnPromise: Boolean
  			//		Return a Promise rather than the instance; supports asynchronous widget creation.
  			// returns:
  			//		Array of instances, or if returnPromise is true, a promise for array of instances
  			//		that resolves when instances have finished initializing.
  
  			// Call widget constructors.   Some may be asynchronous and return promises.
  			var thelist = darray.map(nodes, function(obj){
  				var ctor = obj.ctor || getCtor(obj.types, options.contextRequire);
  				// If we still haven't resolved a ctor, it is fatal now
  				if(!ctor){
  					throw new Error("Unable to resolve constructor for: '" + obj.types.join() + "'");
  				}
  				return this.construct(ctor, obj.node, mixin, options, obj.scripts, obj.inherited);
  			}, this);
  
  			// After all widget construction finishes, call startup on each top level instance if it makes sense (as for
  			// widgets).  Parent widgets will recursively call startup on their (non-top level) children
  			function onConstruct(thelist){
  				if(!mixin._started && !options.noStart){
  					darray.forEach(thelist, function(instance){
  						if(typeof instance.startup === "function" && !instance._started){
  							instance.startup();
  						}
  					});
  				}
  
  				return thelist;
  			}
  
  			if(returnPromise){
  				return all(thelist).then(onConstruct);
  			}else{
  				// Back-compat path, remove for 2.0
  				return onConstruct(thelist);
  			}
  		},
  
  		construct: function(ctor, node, mixin, options, scripts, inherited){
  			// summary:
  			//		Calls new ctor(params, node), where params is the hash of parameters specified on the node,
  			//		excluding data-dojo-type and data-dojo-mixins.   Does not call startup().
  			// ctor: Function
  			//		Widget constructor.
  			// node: DOMNode
  			//		This node will be replaced/attached to by the widget.  It also specifies the arguments to pass to ctor.
  			// mixin: Object?
  			//		Attributes in this object will be passed as parameters to ctor,
  			//		overriding attributes specified on the node.
  			// options: Object?
  			//		An options object used to hold kwArgs for instantiation.   See parse.options argument for details.
  			// scripts: DomNode[]?
  			//		Array of `<script type="dojo/*">` DOMNodes.  If not specified, will search for `<script>` tags inside node.
  			// inherited: Object?
  			//		Settings from dir=rtl or lang=... on a node above this node.   Overrides options.inherited.
  			// returns:
  			//		Instance or Promise for the instance, if markupFactory() itself returned a promise
  
  			var proto = ctor && ctor.prototype;
  			options = options || {};
  
  			// Setup hash to hold parameter settings for this widget.	Start with the parameter
  			// settings inherited from ancestors ("dir" and "lang").
  			// Inherited setting may later be overridden by explicit settings on node itself.
  			var params = {};
  
  			if(options.defaults){
  				// settings for the document itself (or whatever subtree is being parsed)
  				dlang.mixin(params, options.defaults);
  			}
  			if(inherited){
  				// settings from dir=rtl or lang=... on a node above this node
  				dlang.mixin(params, inherited);
  			}
  
  			// Get list of attributes explicitly listed in the markup
  			var attributes;
  			if(has("dom-attributes-explicit")){
  				// Standard path to get list of user specified attributes
  				attributes = node.attributes;
  			}else if(has("dom-attributes-specified-flag")){
  				// Special processing needed for IE8, to skip a few faux values in attributes[]
  				attributes = darray.filter(node.attributes, function(a){
  					return a.specified;
  				});
  			}else{
  				// Special path for IE6-7, avoid (sometimes >100) bogus entries in node.attributes
  				var clone = /^input$|^img$/i.test(node.nodeName) ? node : node.cloneNode(false),
  					attrs = clone.outerHTML.replace(/=[^\s"']+|="[^"]*"|='[^']*'/g, "").replace(/^\s*<[a-zA-Z0-9]*\s*/, "").replace(/\s*>.*$/, "");
  
  				attributes = darray.map(attrs.split(/\s+/), function(name){
  					var lcName = name.toLowerCase();
  					return {
  						name: name,
  						// getAttribute() doesn't work for button.value, returns innerHTML of button.
  						// but getAttributeNode().value doesn't work for the form.encType or li.value
  						value: (node.nodeName == "LI" && name == "value") || lcName == "enctype" ?
  							node.getAttribute(lcName) : node.getAttributeNode(lcName).value
  					};
  				});
  			}
  
  			// Hash to convert scoped attribute name (ex: data-dojo17-params) to something friendly (ex: data-dojo-params)
  			// TODO: remove scope for 2.0
  			var scope = options.scope || dojo._scopeName,
  				attrData = "data-" + scope + "-", // typically "data-dojo-"
  				hash = {};
  			if(scope !== "dojo"){
  				hash[attrData + "props"] = "data-dojo-props";
  				hash[attrData + "type"] = "data-dojo-type";
  				hash[attrData + "mixins"] = "data-dojo-mixins";
  				hash[scope + "type"] = "dojoType";
  				hash[attrData + "id"] = "data-dojo-id";
  			}
  
  			// Read in attributes and process them, including data-dojo-props, data-dojo-type,
  			// dojoAttachPoint, etc., as well as normal foo=bar attributes.
  			var i = 0, item, funcAttrs = [], jsname, extra;
  			while(item = attributes[i++]){
  				var name = item.name,
  					lcName = name.toLowerCase(),
  					value = item.value;
  
  				switch(hash[lcName] || lcName){
  				// Already processed, just ignore
  				case "data-dojo-type":
  				case "dojotype":
  				case "data-dojo-mixins":
  					break;
  
  				// Data-dojo-props.   Save for later to make sure it overrides direct foo=bar settings
  				case "data-dojo-props":
  					extra = value;
  					break;
  
  				// data-dojo-id or jsId. TODO: drop jsId in 2.0
  				case "data-dojo-id":
  				case "jsid":
  					jsname = value;
  					break;
  
  				// For the benefit of _Templated
  				case "data-dojo-attach-point":
  				case "dojoattachpoint":
  					params.dojoAttachPoint = value;
  					break;
  				case "data-dojo-attach-event":
  				case "dojoattachevent":
  					params.dojoAttachEvent = value;
  					break;
  
  				// Special parameter handling needed for IE
  				case "class":
  					params["class"] = node.className;
  					break;
  				case "style":
  					params["style"] = node.style && node.style.cssText;
  					break;
  				default:
  					// Normal attribute, ex: value="123"
  
  					// Find attribute in widget corresponding to specified name.
  					// May involve case conversion, ex: onclick --> onClick
  					if(!(name in proto)){
  						var map = getNameMap(ctor);
  						name = map[lcName] || name;
  					}
  
  					// Set params[name] to value, doing type conversion
  					if(name in proto){
  						switch(typeof proto[name]){
  						case "string":
  							params[name] = value;
  							break;
  						case "number":
  							params[name] = value.length ? Number(value) : NaN;
  							break;
  						case "boolean":
  							// for checked/disabled value might be "" or "checked".	 interpret as true.
  							params[name] = value.toLowerCase() != "false";
  							break;
  						case "function":
  							if(value === "" || value.search(/[^\w\.]+/i) != -1){
  								// The user has specified some text for a function like "return x+5"
  								params[name] = new Function(value);
  							}else{
  								// The user has specified the name of a global function like "myOnClick"
  								// or a single word function "return"
  								params[name] = dlang.getObject(value, false) || new Function(value);
  							}
  							funcAttrs.push(name);	// prevent "double connect", see #15026
  							break;
  						default:
  							var pVal = proto[name];
  							params[name] =
  								(pVal && "length" in pVal) ? (value ? value.split(/\s*,\s*/) : []) :	// array
  									(pVal instanceof Date) ?
  										(value == "" ? new Date("") :	// the NaN of dates
  										value == "now" ? new Date() :	// current date
  										dates.fromISOString(value)) :
  								(pVal instanceof _Url) ? (dojo.baseUrl + value) :
  								myEval(value);
  						}
  					}else{
  						params[name] = value;
  					}
  				}
  			}
  
  			// Remove function attributes from DOMNode to prevent "double connect" problem, see #15026.
  			// Do this as a separate loop since attributes[] is often a live collection (depends on the browser though).
  			for(var j = 0; j < funcAttrs.length; j++){
  				var lcfname = funcAttrs[j].toLowerCase();
  				node.removeAttribute(lcfname);
  				node[lcfname] = null;
  			}
  
  			// Mix things found in data-dojo-props into the params, overriding any direct settings
  			if(extra){
  				try{
  					extra = myEval.call(options.propsThis, "{" + extra + "}");
  					dlang.mixin(params, extra);
  				}catch(e){
  					// give the user a pointer to their invalid parameters. FIXME: can we kill this in production?
  					throw new Error(e.toString() + " in data-dojo-props='" + extra + "'");
  				}
  			}
  
  			// Any parameters specified in "mixin" override everything else.
  			dlang.mixin(params, mixin);
  
  			// Get <script> nodes associated with this widget, if they weren't specified explicitly
  			if(!scripts){
  				scripts = (ctor && (ctor._noScript || proto._noScript) ? [] : query("> script[type^='dojo/']", node));
  			}
  
  			// Process <script type="dojo/*"> script tags
  			// <script type="dojo/method" data-dojo-event="foo"> tags are added to params, and passed to
  			// the widget on instantiation.
  			// <script type="dojo/method"> tags (with no event) are executed after instantiation
  			// <script type="dojo/connect" data-dojo-event="foo"> tags are dojo.connected after instantiation,
  			// and likewise with <script type="dojo/aspect" data-dojo-method="foo">
  			// <script type="dojo/watch" data-dojo-prop="foo"> tags are dojo.watch after instantiation
  			// <script type="dojo/on" data-dojo-event="foo"> tags are dojo.on after instantiation
  			// note: dojo/* script tags cannot exist in self closing widgets, like <input />
  			var aspects = [],	// aspects to connect after instantiation
  				calls = [],		// functions to call after instantiation
  				watches = [],  // functions to watch after instantiation
  				ons = []; // functions to on after instantiation
  
  			if(scripts){
  				for(i = 0; i < scripts.length; i++){
  					var script = scripts[i];
  					node.removeChild(script);
  					// FIXME: drop event="" support in 2.0. use data-dojo-event="" instead
  					var event = (script.getAttribute(attrData + "event") || script.getAttribute("event")),
  						prop = script.getAttribute(attrData + "prop"),
  						method = script.getAttribute(attrData + "method"),
  						advice = script.getAttribute(attrData + "advice"),
  						scriptType = script.getAttribute("type"),
  						nf = this._functionFromScript(script, attrData);
  					if(event){
  						if(scriptType == "dojo/connect"){
  							aspects.push({ method: event, func: nf });
  						}else if(scriptType == "dojo/on"){
  							ons.push({ event: event, func: nf });
  						}else{
  							// <script type="dojo/method" data-dojo-event="foo">
  							// TODO for 2.0: use data-dojo-method="foo" instead (also affects dijit/Declaration)
  							params[event] = nf;
  						}
  					}else if(scriptType == "dojo/aspect"){
  						aspects.push({ method: method, advice: advice, func: nf });
  					}else if(scriptType == "dojo/watch"){
  						watches.push({ prop: prop, func: nf });
  					}else{
  						calls.push(nf);
  					}
  				}
  			}
  
  			// create the instance
  			var markupFactory = ctor.markupFactory || proto.markupFactory;
  			var instance = markupFactory ? markupFactory(params, node, ctor) : new ctor(params, node);
  
  			function onInstantiate(instance){
  				// map it to the JS namespace if that makes sense
  				if(jsname){
  					dlang.setObject(jsname, instance);
  				}
  
  				// process connections and startup functions
  				for(i = 0; i < aspects.length; i++){
  					aspect[aspects[i].advice || "after"](instance, aspects[i].method, dlang.hitch(instance, aspects[i].func), true);
  				}
  				for(i = 0; i < calls.length; i++){
  					calls[i].call(instance);
  				}
  				for(i = 0; i < watches.length; i++){
  					instance.watch(watches[i].prop, watches[i].func);
  				}
  				for(i = 0; i < ons.length; i++){
  					don(instance, ons[i].event, ons[i].func);
  				}
  
  				return instance;
  			}
  
  			if(instance.then){
  				return instance.then(onInstantiate);
  			}else{
  				return onInstantiate(instance);
  			}
  		},
  
  		scan: function(root, options){
  			// summary:
  			//		Scan a DOM tree and return an array of objects representing the DOMNodes
  			//		that need to be turned into widgets.
  			// description:
  			//		Search specified node (or document root node) recursively for class instances
  			//		and return an array of objects that represent potential widgets to be
  			//		instantiated. Searches for either data-dojo-type="MID" or dojoType="MID" where
  			//		"MID" is a module ID like "dijit/form/Button" or a fully qualified Class name
  			//		like "dijit/form/Button".  If the MID is not currently available, scan will
  			//		attempt to require() in the module.
  			//
  			//		See parser.parse() for details of markup.
  			// root: DomNode?
  			//		A default starting root node from which to start the parsing. Can be
  			//		omitted, defaulting to the entire document. If omitted, the `options`
  			//		object can be passed in this place. If the `options` object has a
  			//		`rootNode` member, that is used.
  			// options: Object
  			//		a kwArgs options object, see parse() for details
  			//
  			// returns: Promise
  			//		A promise that is resolved with the nodes that have been parsed.
  
  			var list = [], // Output List
  				mids = [], // An array of modules that are not yet loaded
  				midsHash = {}; // Used to keep the mids array unique
  
  			var dojoType = (options.scope || dojo._scopeName) + "Type", // typically "dojoType"
  				attrData = "data-" + (options.scope || dojo._scopeName) + "-", // typically "data-dojo-"
  				dataDojoType = attrData + "type", // typically "data-dojo-type"
  				dataDojoTextDir = attrData + "textdir", // typically "data-dojo-textdir"
  				dataDojoMixins = attrData + "mixins";					// typically "data-dojo-mixins"
  
  			// Info on DOMNode currently being processed
  			var node = root.firstChild;
  
  			// Info on parent of DOMNode currently being processed
  			//	- inherited: dir, lang, and textDir setting of parent, or inherited by parent
  			//	- parent: pointer to identical structure for my parent (or null if no parent)
  			//	- scripts: if specified, collects <script type="dojo/..."> type nodes from children
  			var inherited = options.inherited;
  			if(!inherited){
  				function findAncestorAttr(node, attr){
  					return (node.getAttribute && node.getAttribute(attr)) ||
  						(node.parentNode && findAncestorAttr(node.parentNode, attr));
  				}
  
  				inherited = {
  					dir: findAncestorAttr(root, "dir"),
  					lang: findAncestorAttr(root, "lang"),
  					textDir: findAncestorAttr(root, dataDojoTextDir)
  				};
  				for(var key in inherited){
  					if(!inherited[key]){
  						delete inherited[key];
  					}
  				}
  			}
  
  			// Metadata about parent node
  			var parent = {
  				inherited: inherited
  			};
  
  			// For collecting <script type="dojo/..."> type nodes (when null, we don't need to collect)
  			var scripts;
  
  			// when true, only look for <script type="dojo/..."> tags, and don't recurse to children
  			var scriptsOnly;
  
  			function getEffective(parent){
  				// summary:
  				//		Get effective dir, lang, textDir settings for specified obj
  				//		(matching "parent" object structure above), and do caching.
  				//		Take care not to return null entries.
  				if(!parent.inherited){
  					parent.inherited = {};
  					var node = parent.node,
  						grandparent = getEffective(parent.parent);
  					var inherited = {
  						dir: node.getAttribute("dir") || grandparent.dir,
  						lang: node.getAttribute("lang") || grandparent.lang,
  						textDir: node.getAttribute(dataDojoTextDir) || grandparent.textDir
  					};
  					for(var key in inherited){
  						if(inherited[key]){
  							parent.inherited[key] = inherited[key];
  						}
  					}
  				}
  				return parent.inherited;
  			}
  
  			// DFS on DOM tree, collecting nodes with data-dojo-type specified.
  			while(true){
  				if(!node){
  					// Finished this level, continue to parent's next sibling
  					if(!parent || !parent.node){
  						break;
  					}
  					node = parent.node.nextSibling;
  					scriptsOnly = false;
  					parent = parent.parent;
  					scripts = parent.scripts;
  					continue;
  				}
  
  				if(node.nodeType != 1){
  					// Text or comment node, skip to next sibling
  					node = node.nextSibling;
  					continue;
  				}
  
  				if(scripts && node.nodeName.toLowerCase() == "script"){
  					// Save <script type="dojo/..."> for parent, then continue to next sibling
  					type = node.getAttribute("type");
  					if(type && /^dojo\/\w/i.test(type)){
  						scripts.push(node);
  					}
  					node = node.nextSibling;
  					continue;
  				}
  				if(scriptsOnly){
  					// scriptsOnly flag is set, we have already collected scripts if the parent wants them, so now we shouldn't
  					// continue further analysis of the node and will continue to the next sibling
  					node = node.nextSibling;
  					continue;
  				}
  
  				// Check for data-dojo-type attribute, fallback to backward compatible dojoType
  				// TODO: Remove dojoType in 2.0
  				var type = node.getAttribute(dataDojoType) || node.getAttribute(dojoType);
  
  				// Short circuit for leaf nodes containing nothing [but text]
  				var firstChild = node.firstChild;
  				if(!type && (!firstChild || (firstChild.nodeType == 3 && !firstChild.nextSibling))){
  					node = node.nextSibling;
  					continue;
  				}
  
  				// Meta data about current node
  				var current;
  
  				var ctor = null;
  				if(type){
  					// If dojoType/data-dojo-type specified, add to output array of nodes to instantiate.
  					var mixinsValue = node.getAttribute(dataDojoMixins),
  						types = mixinsValue ? [type].concat(mixinsValue.split(/\s*,\s*/)) : [type];
  
  					// Note: won't find classes declared via dojo/Declaration or any modules that haven't been
  					// loaded yet so use try/catch to avoid throw from require()
  					try{
  						ctor = getCtor(types, options.contextRequire);
  					}catch(e){}
  
  					// If the constructor was not found, check to see if it has modules that can be loaded
  					if(!ctor){
  						darray.forEach(types, function(t){
  							if(~t.indexOf('/') && !midsHash[t]){
  								// If the type looks like a MID and it currently isn't in the array of MIDs to load, add it.
  								midsHash[t] = true;
  								mids[mids.length] = t;
  							}
  						});
  					}
  
  					var childScripts = ctor && !ctor.prototype._noScript ? [] : null; // <script> nodes that are parent's children
  
  					// Setup meta data about this widget node, and save it to list of nodes to instantiate
  					current = {
  						types: types,
  						ctor: ctor,
  						parent: parent,
  						node: node,
  						scripts: childScripts
  					};
  					current.inherited = getEffective(current); // dir & lang settings for current node, explicit or inherited
  					list.push(current);
  				}else{
  					// Meta data about this non-widget node
  					current = {
  						node: node,
  						scripts: scripts,
  						parent: parent
  					};
  				}
  
  				// Recurse, collecting <script type="dojo/..."> children, and also looking for
  				// descendant nodes with dojoType specified (unless the widget has the stopParser flag).
  				// When finished with children, go to my next sibling.
  				scripts = childScripts;
  				scriptsOnly = node.stopParser || (ctor && ctor.prototype.stopParser && !(options.template));
  				parent = current;
  				node = firstChild;
  			}
  
  			var d = new Deferred();
  
  			// If there are modules to load then require them in
  			if(mids.length){
  				// Warn that there are modules being auto-required
  				if( true ){
  					console.warn("WARNING: Modules being Auto-Required: " + mids.join(", "));
  				}
  				var r = options.contextRequire || require;
  				r(mids, function(){
  					// Go through list of widget nodes, filling in missing constructors, and filtering out nodes that shouldn't
  					// be instantiated due to a stopParser flag on an ancestor that we belatedly learned about due to
  					// auto-require of a module like ContentPane.   Assumes list is in DFS order.
  					d.resolve(darray.filter(list, function(widget){
  						if(!widget.ctor){
  							// Attempt to find the constructor again.   Still won't find classes defined via
  							// dijit/Declaration so need to try/catch.
  							try{
  								widget.ctor = getCtor(widget.types, options.contextRequire);
  							}catch(e){}
  						}
  
  						// Get the parent widget
  						var parent = widget.parent;
  						while(parent && !parent.types){
  							parent = parent.parent;
  						}
  
  						// Return false if this node should be skipped due to stopParser on an ancestor.
  						// Since list[] is in DFS order, this loop will always set parent.instantiateChildren before
  						// trying to compute widget.instantiate.
  						var proto = widget.ctor && widget.ctor.prototype;
  						widget.instantiateChildren = !(proto && proto.stopParser && !(options.template));
  						widget.instantiate = !parent || (parent.instantiate && parent.instantiateChildren);
  						return widget.instantiate;
  					}));
  				});
  			}else{
  				// There were no modules to load, so just resolve with the parsed nodes.   This separate code path is for
  				// efficiency, to avoid running the require() and the callback code above.
  				d.resolve(list);
  			}
  
  			// Return the promise
  			return d.promise;
  		},
  
  		_require: function(/*DOMNode*/ script, /*Object?*/ options){
  			// summary:
  			//		Helper for _scanAMD().  Takes a `<script type=dojo/require>bar: "acme/bar", ...</script>` node,
  			//		calls require() to load the specified modules and (asynchronously) assign them to the specified global
  			//		variables, and returns a Promise for when that operation completes.
  			//
  			//		In the example above, it is effectively doing a require(["acme/bar", ...], function(a){ bar = a; }).
  
  			var hash = myEval("{" + script.innerHTML + "}"), // can't use dojo/json::parse() because maybe no quotes
  				vars = [],
  				mids = [],
  				d = new Deferred();
  
  			var contextRequire = (options && options.contextRequire) || require;
  
  			for(var name in hash){
  				vars.push(name);
  				mids.push(hash[name]);
  			}
  
  			contextRequire(mids, function(){
  				for(var i = 0; i < vars.length; i++){
  					dlang.setObject(vars[i], arguments[i]);
  				}
  				d.resolve(arguments);
  			});
  
  			return d.promise;
  		},
  
  		_scanAmd: function(root, options){
  			// summary:
  			//		Scans the DOM for any declarative requires and returns their values.
  			// description:
  			//		Looks for `<script type=dojo/require>bar: "acme/bar", ...</script>` node, calls require() to load the
  			//		specified modules and (asynchronously) assign them to the specified global variables,
  			//		and returns a Promise for when those operations complete.
  			// root: DomNode
  			//		The node to base the scan from.
  			// options: Object?
  			//		a kwArgs options object, see parse() for details
  
  			// Promise that resolves when all the <script type=dojo/require> nodes have finished loading.
  			var deferred = new Deferred(),
  				promise = deferred.promise;
  			deferred.resolve(true);
  
  			var self = this;
  			query("script[type='dojo/require']", root).forEach(function(node){
  				// Fire off require() call for specified modules.  Chain this require to fire after
  				// any previous requires complete, so that layers can be loaded before individual module require()'s fire.
  				promise = promise.then(function(){
  					return self._require(node, options);
  				});
  
  				// Remove from DOM so it isn't seen again
  				node.parentNode.removeChild(node);
  			});
  
  			return promise;
  		},
  
  		parse: function(rootNode, options){
  			// summary:
  			//		Scan the DOM for class instances, and instantiate them.
  			// description:
  			//		Search specified node (or root node) recursively for class instances,
  			//		and instantiate them. Searches for either data-dojo-type="Class" or
  			//		dojoType="Class" where "Class" is a a fully qualified class name,
  			//		like `dijit/form/Button`
  			//
  			//		Using `data-dojo-type`:
  			//		Attributes using can be mixed into the parameters used to instantiate the
  			//		Class by using a `data-dojo-props` attribute on the node being converted.
  			//		`data-dojo-props` should be a string attribute to be converted from JSON.
  			//
  			//		Using `dojoType`:
  			//		Attributes are read from the original domNode and converted to appropriate
  			//		types by looking up the Class prototype values. This is the default behavior
  			//		from Dojo 1.0 to Dojo 1.5. `dojoType` support is deprecated, and will
  			//		go away in Dojo 2.0.
  			// rootNode: DomNode?
  			//		A default starting root node from which to start the parsing. Can be
  			//		omitted, defaulting to the entire document. If omitted, the `options`
  			//		object can be passed in this place. If the `options` object has a
  			//		`rootNode` member, that is used.
  			// options: Object?
  			//		A hash of options.
  			//
  			//		- noStart: Boolean?:
  			//			when set will prevent the parser from calling .startup()
  			//			when locating the nodes.
  			//		- rootNode: DomNode?:
  			//			identical to the function's `rootNode` argument, though
  			//			allowed to be passed in via this `options object.
  			//		- template: Boolean:
  			//			If true, ignores ContentPane's stopParser flag and parses contents inside of
  			//			a ContentPane inside of a template.   This allows dojoAttachPoint on widgets/nodes
  			//			nested inside the ContentPane to work.
  			//		- inherited: Object:
  			//			Hash possibly containing dir and lang settings to be applied to
  			//			parsed widgets, unless there's another setting on a sub-node that overrides
  			//		- scope: String:
  			//			Root for attribute names to search for.   If scopeName is dojo,
  			//			will search for data-dojo-type (or dojoType).   For backwards compatibility
  			//			reasons defaults to dojo._scopeName (which is "dojo" except when
  			//			multi-version support is used, when it will be something like dojo16, dojo20, etc.)
  			//		- propsThis: Object:
  			//			If specified, "this" referenced from data-dojo-props will refer to propsThis.
  			//			Intended for use from the widgets-in-template feature of `dijit._WidgetsInTemplateMixin`
  			//		- contextRequire: Function:
  			//			If specified, this require is utilised for looking resolving modules instead of the
  			//			`dojo/parser` context `require()`.  Intended for use from the widgets-in-template feature of
  			//			`dijit._WidgetsInTemplateMixin`.
  			// returns: Mixed
  			//		Returns a blended object that is an array of the instantiated objects, but also can include
  			//		a promise that is resolved with the instantiated objects.  This is done for backwards
  			//		compatibility.  If the parser auto-requires modules, it will always behave in a promise
  			//		fashion and `parser.parse().then(function(instances){...})` should be used.
  			// example:
  			//		Parse all widgets on a page:
  			//	|		parser.parse();
  			// example:
  			//		Parse all classes within the node with id="foo"
  			//	|		parser.parse(dojo.byId('foo'));
  			// example:
  			//		Parse all classes in a page, but do not call .startup() on any
  			//		child
  			//	|		parser.parse({ noStart: true })
  			// example:
  			//		Parse all classes in a node, but do not call .startup()
  			//	|		parser.parse(someNode, { noStart:true });
  			//	|		// or
  			//	|		parser.parse({ noStart:true, rootNode: someNode });
  
  			// determine the root node and options based on the passed arguments.
  			var root;
  			if(!options && rootNode && rootNode.rootNode){
  				options = rootNode;
  				root = options.rootNode;
  			}else if(rootNode && dlang.isObject(rootNode) && !("nodeType" in rootNode)){
  				options = rootNode;
  			}else{
  				root = rootNode;
  			}
  			root = root ? dom.byId(root) : dwindow.body();
  
  			options = options || {};
  
  			var mixin = options.template ? { template: true } : {},
  				instances = [],
  				self = this;
  
  			// First scan for any <script type=dojo/require> nodes, and execute.
  			// Then scan for all nodes with data-dojo-type, and load any unloaded modules.
  			// Then build the object instances.  Add instances to already existing (but empty) instances[] array,
  			// which may already have been returned to caller.  Also, use otherwise to collect and throw any errors
  			// that occur during the parse().
  			var p =
  				this._scanAmd(root, options).then(function(){
  					return self.scan(root, options);
  				}).then(function(parsedNodes){
  					return self._instantiate(parsedNodes, mixin, options, true);
  				}).then(function(_instances){
  					// Copy the instances into the instances[] array we declared above, and are accessing as
  					// our return value.
  					return instances = instances.concat(_instances);
  				}).otherwise(function(e){
  					// TODO Modify to follow better pattern for promise error management when available
  					console.error("dojo/parser::parse() error", e);
  					throw e;
  				});
  
  			// Blend the array with the promise
  			dlang.mixin(instances, p);
  			return instances;
  		}
  	};
  
  	if( 1 ){
  		dojo.parser = parser;
  	}
  
  	// Register the parser callback. It should be the first callback
  	// after the a11y test.
  	if(config.parseOnLoad){
  		ready(100, parser, "parse");
  	}
  
  	return parser;
  });
  