text: define(["./_base/kernel", "./_base/lang", "./_base/array", "./_base/declare", "./dom", "./dom-construct", "./parser"],
  	function(kernel, lang, darray, declare, dom, domConstruct, parser){
  	// module:
  	//		dojo/html
  
  	// the parser might be needed..
  
  	// idCounter is incremented with each instantiation to allow assignment of a unique id for tracking, logging purposes
  	var idCounter = 0;
  
  	var html = {
  		// summary:
  		//		TODOC
  
  		_secureForInnerHtml: function(/*String*/ cont){
  			// summary:
  			//		removes !DOCTYPE and title elements from the html string.
  			//
  			//		khtml is picky about dom faults, you can't attach a style or `<title>` node as child of body
  			//		must go into head, so we need to cut out those tags
  			// cont:
  			//		An html string for insertion into the dom
  			//
  			return cont.replace(/(?:\s*<!DOCTYPE\s[^>]+>|<title[^>]*>[\s\S]*?<\/title>)/ig, ""); // String
  		},
  
  		// Deprecated, should use dojo/dom-constuct.empty() directly, remove in 2.0.
  		_emptyNode: domConstruct.empty,
  
  		_setNodeContent: function(/*DomNode*/ node, /*String|DomNode|NodeList*/ cont){
  			// summary:
  			//		inserts the given content into the given node
  			// node:
  			//		the parent element
  			// content:
  			//		the content to be set on the parent element.
  			//		This can be an html string, a node reference or a NodeList, dojo/NodeList, Array or other enumerable list of nodes
  
  			// always empty
  			domConstruct.empty(node);
  
  			if(cont){
  				if(typeof cont == "number"){
  					cont = cont.toString();
  				}
  				if(typeof cont == "string"){
  					cont = domConstruct.toDom(cont, node.ownerDocument);
  				}
  				if(!cont.nodeType && lang.isArrayLike(cont)){
  					// handle as enumerable, but it may shrink as we enumerate it
  					for(var startlen=cont.length, i=0; i<cont.length; i=startlen==cont.length ? i+1 : 0){
  						domConstruct.place( cont[i], node, "last");
  					}
  				}else{
  					// pass nodes, documentFragments and unknowns through to dojo.place
  					domConstruct.place(cont, node, "last");
  				}
  			}
  
  			// return DomNode
  			return node;
  		},
  
  		// we wrap up the content-setting operation in a object
  		_ContentSetter: declare("dojo.html._ContentSetter", null, {
  			// node: DomNode|String
  			//		An node which will be the parent element that we set content into
  			node: "",
  
  			// content: String|DomNode|DomNode[]
  			//		The content to be placed in the node. Can be an HTML string, a node reference, or a enumerable list of nodes
  			content: "",
  
  			// id: String?
  			//		Usually only used internally, and auto-generated with each instance
  			id: "",
  
  			// cleanContent: Boolean
  			//		Should the content be treated as a full html document,
  			//		and the real content stripped of <html>, <body> wrapper before injection
  			cleanContent: false,
  
  			// extractContent: Boolean
  			//		Should the content be treated as a full html document,
  			//		and the real content stripped of `<html> <body>` wrapper before injection
  			extractContent: false,
  
  			// parseContent: Boolean
  			//		Should the node by passed to the parser after the new content is set
  			parseContent: false,
  
  			// parserScope: String
  			//		Flag passed to parser.	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.)
  			parserScope: kernel._scopeName,
  
  			// startup: Boolean
  			//		Start the child widgets after parsing them.	  Only obeyed if parseContent is true.
  			startup: true,
  
  			// lifecycle methods
  			constructor: function(/*Object*/ params, /*String|DomNode*/ node){
  				// summary:
  				//		Provides a configurable, extensible object to wrap the setting on content on a node
  				//		call the set() method to actually set the content..
  
  				// the original params are mixed directly into the instance "this"
  				lang.mixin(this, params || {});
  
  				// give precedence to params.node vs. the node argument
  				// and ensure its a node, not an id string
  				node = this.node = dom.byId( this.node || node );
  
  				if(!this.id){
  					this.id = [
  						"Setter",
  						(node) ? node.id || node.tagName : "",
  						idCounter++
  					].join("_");
  				}
  			},
  			set: function(/* String|DomNode|NodeList? */ cont, /*Object?*/ params){
  				// summary:
  				//		front-end to the set-content sequence
  				// cont:
  				//		An html string, node or enumerable list of nodes for insertion into the dom
  				//		If not provided, the object's content property will be used
  				if(undefined !== cont){
  					this.content = cont;
  				}
  				if(typeof cont == 'number'){
  					cont = cont.toString();
  				}
  				// in the re-use scenario, set needs to be able to mixin new configuration
  				if(params){
  					this._mixin(params);
  				}
  
  				this.onBegin();
  				this.setContent();
  
  				var ret = this.onEnd();
  
  				if(ret && ret.then){
  					// Make dojox/html/_ContentSetter.set() return a Promise that resolves when load and parse complete.
  					return ret;
  				}else{
  					// Vanilla dojo/html._ContentSetter.set() returns a DOMNode for back compat.   For 2.0, switch it to
  					// return a Deferred like above.
  					return this.node;
  				}
  			},
  
  			setContent: function(){
  				// summary:
  				//		sets the content on the node
  
  				var node = this.node;
  				if(!node){
  					// can't proceed
  					throw new Error(this.declaredClass + ": setContent given no node");
  				}
  				try{
  					node = html._setNodeContent(node, this.content);
  				}catch(e){
  					// check if a domfault occurs when we are appending this.errorMessage
  					// like for instance if domNode is a UL and we try append a DIV
  
  					// FIXME: need to allow the user to provide a content error message string
  					var errMess = this.onContentError(e);
  					try{
  						node.innerHTML = errMess;
  					}catch(e){
  						console.error('Fatal ' + this.declaredClass + '.setContent could not change content due to '+e.message, e);
  					}
  				}
  				// always put back the node for the next method
  				this.node = node; // DomNode
  			},
  
  			empty: function(){
  				// summary:
  				//		cleanly empty out existing content
  
  				// If there is a parse in progress, cancel it.
  				if(this.parseDeferred){
  					if(!this.parseDeferred.isResolved()){
  						this.parseDeferred.cancel();
  					}
  					delete this.parseDeferred;
  				}
  
  				// destroy any widgets from a previous run
  				// NOTE: if you don't want this you'll need to empty
  				// the parseResults array property yourself to avoid bad things happening
  				if(this.parseResults && this.parseResults.length){
  					darray.forEach(this.parseResults, function(w){
  						if(w.destroy){
  							w.destroy();
  						}
  					});
  					delete this.parseResults;
  				}
  				// this is fast, but if you know its already empty or safe, you could
  				// override empty to skip this step
  				domConstruct.empty(this.node);
  			},
  
  			onBegin: function(){
  				// summary:
  				//		Called after instantiation, but before set();
  				//		It allows modification of any of the object properties -
  				//		including the node and content provided - before the set operation actually takes place
  				//		This default implementation checks for cleanContent and extractContent flags to
  				//		optionally pre-process html string content
  				var cont = this.content;
  
  				if(lang.isString(cont)){
  					if(this.cleanContent){
  						cont = html._secureForInnerHtml(cont);
  					}
  
  					if(this.extractContent){
  						var match = cont.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
  						if(match){ cont = match[1]; }
  					}
  				}
  
  				// clean out the node and any cruft associated with it - like widgets
  				this.empty();
  
  				this.content = cont;
  				return this.node; // DomNode
  			},
  
  			onEnd: function(){
  				// summary:
  				//		Called after set(), when the new content has been pushed into the node
  				//		It provides an opportunity for post-processing before handing back the node to the caller
  				//		This default implementation checks a parseContent flag to optionally run the dojo parser over the new content
  				if(this.parseContent){
  					// populates this.parseResults and this.parseDeferred if you need those..
  					this._parse();
  				}
  				return this.node; // DomNode
  				// TODO: for 2.0 return a Promise indicating that the parse completed.
  			},
  
  			tearDown: function(){
  				// summary:
  				//		manually reset the Setter instance if its being re-used for example for another set()
  				// description:
  				//		tearDown() is not called automatically.
  				//		In normal use, the Setter instance properties are simply allowed to fall out of scope
  				//		but the tearDown method can be called to explicitly reset this instance.
  				delete this.parseResults;
  				delete this.parseDeferred;
  				delete this.node;
  				delete this.content;
  			},
  
  			onContentError: function(err){
  				return "Error occurred setting content: " + err;
  			},
  
  			onExecError: function(err){
  				return "Error occurred executing scripts: " + err;
  			},
  
  			_mixin: function(params){
  				// mix properties/methods into the instance
  				// TODO: the intention with tearDown is to put the Setter's state
  				// back to that of the original constructor (vs. deleting/resetting everything regardless of ctor params)
  				// so we could do something here to move the original properties aside for later restoration
  				var empty = {}, key;
  				for(key in params){
  					if(key in empty){ continue; }
  					// TODO: here's our opportunity to mask the properties we don't consider configurable/overridable
  					// .. but history shows we'll almost always guess wrong
  					this[key] = params[key];
  				}
  			},
  			_parse: function(){
  				// summary:
  				//		runs the dojo parser over the node contents, storing any results in this.parseResults
  				//		and the parse promise in this.parseDeferred
  				//		Any errors resulting from parsing are passed to _onError for handling
  
  				var rootNode = this.node;
  				try{
  					// store the results (widgets, whatever) for potential retrieval
  					var inherited = {};
  					darray.forEach(["dir", "lang", "textDir"], function(name){
  						if(this[name]){
  							inherited[name] = this[name];
  						}
  					}, this);
  					var self = this;
  					this.parseDeferred = parser.parse({
  						rootNode: rootNode,
  						noStart: !this.startup,
  						inherited: inherited,
  						scope: this.parserScope
  					}).then(function(results){
  							return self.parseResults = results;
  						}, function(e){
  							self._onError('Content', e, "Error parsing in _ContentSetter#" + this.id);
  						});
  				}catch(e){
  					this._onError('Content', e, "Error parsing in _ContentSetter#" + this.id);
  				}
  			},
  
  			_onError: function(type, err, consoleText){
  				// summary:
  				//		shows user the string that is returned by on[type]Error
  				//		override/implement on[type]Error and return your own string to customize
  				var errText = this['on' + type + 'Error'].call(this, err);
  				if(consoleText){
  					console.error(consoleText, err);
  				}else if(errText){ // a empty string won't change current content
  					html._setNodeContent(this.node, errText, true);
  				}
  			}
  		}), // end declare()
  
  		set: function(/*DomNode*/ node, /*String|DomNode|NodeList*/ cont, /*Object?*/ params){
  			// summary:
  			//		inserts (replaces) the given content into the given node. dojo/dom-construct.place(cont, node, "only")
  			//		may be a better choice for simple HTML insertion.
  			// description:
  			//		Unless you need to use the params capabilities of this method, you should use
  			//		dojo/dom-construct.place(cont, node, "only"). dojo/dom-construct..place() has more robust support for injecting
  			//		an HTML string into the DOM, but it only handles inserting an HTML string as DOM
  			//		elements, or inserting a DOM node. dojo/dom-construct..place does not handle NodeList insertions
  			//		dojo/dom-construct.place(cont, node, "only"). dojo/dom-construct.place() has more robust support for injecting
  			//		an HTML string into the DOM, but it only handles inserting an HTML string as DOM
  			//		elements, or inserting a DOM node. dojo/dom-construct.place does not handle NodeList insertions
  			//		or the other capabilities as defined by the params object for this method.
  			// node:
  			//		the parent element that will receive the content
  			// cont:
  			//		the content to be set on the parent element.
  			//		This can be an html string, a node reference or a NodeList, dojo/NodeList, Array or other enumerable list of nodes
  			// params:
  			//		Optional flags/properties to configure the content-setting. See dojo/html/_ContentSetter
  			// example:
  			//		A safe string/node/nodelist content replacement/injection with hooks for extension
  			//		Example Usage:
  			//	|	html.set(node, "some string");
  			//	|	html.set(node, contentNode, {options});
  			//	|	html.set(node, myNode.childNodes, {options});
  			if(undefined == cont){
  				console.warn("dojo.html.set: no cont argument provided, using empty string");
  				cont = "";
  			}
  			if (typeof cont == 'number'){
  				cont = cont.toString();
  			}
  			if(!params){
  				// simple and fast
  				return html._setNodeContent(node, cont, true);
  			}else{
  				// more options but slower
  				// note the arguments are reversed in order, to match the convention for instantiation via the parser
  				var op = new html._ContentSetter(lang.mixin(
  					params,
  					{ content: cont, node: node }
  				));
  				return op.set();
  			}
  		}
  	};
  	lang.setObject("dojo.html", html);
  
  	return html;
  });
  