[Pkg-javascript-commits] [dojo] 02/87: Set svn:eol-style to 'native' on files missing it. refs #7776 !strict

David Prévot taffit at moszumanska.debian.org
Thu Aug 21 17:39:13 UTC 2014


This is an automated email from the git hooks/post-receive script.

taffit pushed a commit to annotated tag 1.7.5
in repository dojo.

commit 961b9d4eae0af09e6faba2eec1510c453decfc00
Author: Bryan Forbes <bryan at reigndropsfall.net>
Date:   Fri Oct 28 20:54:48 2011 +0000

    Set svn:eol-style to 'native' on files missing it. refs #7776 !strict
    
    
    git-svn-id: http://svn.dojotoolkit.org/src/branches/1.7/dojo@26925 560b804f-0ae3-0310-86f3-f6aa0a117693
---
 Evented.js          |   64 +-
 aspect.js           |  408 +++----
 json.js             |  298 +++---
 keys.js             |  160 +--
 mouse.js            |  254 ++---
 on.js               |  946 ++++++++--------
 query.js            | 1424 ++++++++++++-------------
 selector/_loader.js |   90 +-
 selector/acme.js    | 2960 +++++++++++++++++++++++++--------------------------
 selector/lite.js    |  528 ++++-----
 store/api/Store.js  |  594 +++++------
 tests/aspect.js     |  238 ++---
 tests/json.js       |  332 +++---
 tests/on.js         |  458 ++++----
 topic.js            |   66 +-
 15 files changed, 4410 insertions(+), 4410 deletions(-)

diff --git a/Evented.js b/Evented.js
index 955cbc4..420dfca 100644
--- a/Evented.js
+++ b/Evented.js
@@ -1,32 +1,32 @@
-define(["./aspect", "./on"], function(aspect, on){
-	// summary:
-	//		The export of this module is a class that can be used as a mixin or base class, 
-	// 		to add on() and emit() methods to a class
-	// 		for listening for events and emiting events:
-	// 		|define(["dojo/Evented"], function(Evented){
-	// 		|	var EventedWidget = dojo.declare([Evented, dijit._Widget], {...});
-	//		|	widget = new EventedWidget();
-	//		|	widget.on("open", function(event){
-	//		|	... do something with event
-	//		|	 });
-	//		|
-	//		|	widget.emit("open", {name:"some event", ...});
-
- 	"use strict";
- 	var after = aspect.after;
-	function Evented(){
-	}
-	Evented.prototype = {
-		on: function(type, listener){
-			return on.parse(this, type, listener, function(target, type){
-				return after(target, 'on' + type, listener, true);
-			});
-		},
-		emit: function(type, event){
-			var args = [this];
-			args.push.apply(args, arguments);
-			return on.emit.apply(on, args);
-		}
-	};
-	return Evented;
-});
+define(["./aspect", "./on"], function(aspect, on){
+	// summary:
+	//		The export of this module is a class that can be used as a mixin or base class, 
+	// 		to add on() and emit() methods to a class
+	// 		for listening for events and emiting events:
+	// 		|define(["dojo/Evented"], function(Evented){
+	// 		|	var EventedWidget = dojo.declare([Evented, dijit._Widget], {...});
+	//		|	widget = new EventedWidget();
+	//		|	widget.on("open", function(event){
+	//		|	... do something with event
+	//		|	 });
+	//		|
+	//		|	widget.emit("open", {name:"some event", ...});
+
+ 	"use strict";
+ 	var after = aspect.after;
+	function Evented(){
+	}
+	Evented.prototype = {
+		on: function(type, listener){
+			return on.parse(this, type, listener, function(target, type){
+				return after(target, 'on' + type, listener, true);
+			});
+		},
+		emit: function(type, event){
+			var args = [this];
+			args.push.apply(args, arguments);
+			return on.emit.apply(on, args);
+		}
+	};
+	return Evented;
+});
diff --git a/aspect.js b/aspect.js
index 163febd..faa149a 100644
--- a/aspect.js
+++ b/aspect.js
@@ -1,204 +1,204 @@
-define([], function(){
-
-// TODOC: after/before/around return object
-// TODOC: after/before/around param types. 
-
-/*=====
-	dojo.aspect = {
-		// summary: provides aspect oriented programming functionality, allowing for
-		//		one to add before, around, or after advice on existing methods.
-		//
-		// example:
-		//	|	define(["dojo/aspect"], function(aspect){
-		//	|		var signal = aspect.after(targetObject, "methodName", function(someArgument){
-		//	|			this will be called when targetObject.methodName() is called, after the original function is called
-		//	|		});
-		//
-		// example:
-		//	The returned signal object can be used to cancel the advice.
-		//	|	signal.remove(); // this will stop the advice from being executed anymore
-		//	|	aspect.before(targetObject, "methodName", function(someArgument){
-		//	|		// this will be called when targetObject.methodName() is called, before the original function is called
-		//	|	 });
-		
-		after: function(target, methodName, advice, receiveArguments){
-			// summary: The "after" export of the aspect module is a function that can be used to attach
-			//		"after" advice to a method. This function will be executed after the original method
-			//		is executed. By default the function will be called with a single argument, the return
-			//		value of the original method, or the the return value of the last executed advice (if a previous one exists).
-			//		The fourth (optional) argument can be set to true to so the function receives the original
-			//		arguments (from when the original method was called) rather than the return value.
-			//		If there are multiple "after" advisors, they are executed in the order they were registered.
-			// target: Object
-			//		This is the target object
-			// methodName: String
-			//		This is the name of the method to attach to.
-			// advice: Function
-			//		This is function to be called after the original method
-			// receiveArguments: Boolean?
-			//		If this is set to true, the advice function receives the original arguments (from when the original mehtod
-			//		was called) rather than the return value of the original/previous method.
-			// returns:
-			//		A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will
-			//		stop the advice function from being executed.
-		},
-		
-		before: function(target, methodName, advice){
-			// summary: The "before" export of the aspect module is a function that can be used to attach
-			//		"before" advice to a method. This function will be executed before the original method
-			//		is executed. This function will be called with the arguments used to call the method.
-			//		This function may optionally return an array as the new arguments to use to call
-			//		the original method (or the previous, next-to-execute before advice, if one exists).
-			//		If the before method doesn't return anything (returns undefined) the original arguments
-			//		will be preserved.
-			//		If there are multiple "before" advisors, they are executed in the reverse order they were registered.
-			//
-			// target: Object
-			//		This is the target object
-			// methodName: String
-			//		This is the name of the method to attach to.
-			// advice: Function
-			//		This is function to be called before the original method	 
-		},
-
-		around: function(target, methodName, advice){
-			// summary: The "around" export of the aspect module is a function that can be used to attach
-			//		"around" advice to a method. The advisor function is immediately executed when
-			//		the around() is called, is passed a single argument that is a function that can be
-			//		called to continue execution of the original method (or the next around advisor).
-			//		The advisor function should return a function, and this function will be called whenever
-			//		the method is called. It will be called with the arguments used to call the method.
-			//		Whatever this function returns will be returned as the result of the method call (unless after advise changes it).
-			//
-			// example:
-			//		If there are multiple "around" advisors, the most recent one is executed first,
-			//		which can then delegate to the next one and so on. For example:
-			//		|	around(obj, "foo", function(originalFoo){
-			//		|		return function(){
-			//		|			var start = new Date().getTime();
-			//		|			var results = originalFoo.apply(this, arguments); // call the original
-			//		|			var end = new Date().getTime();
-			//		|			console.log("foo execution took " + (end - start) + " ms");
-			//		|			return results;
-			//		|		};
-			//		|	});
-			//
-			// target: Object
-			//		This is the target object
-			// methodName: String
-			//		This is the name of the method to attach to.
-			// advice: Function
-			//		This is function to be called around the original method
-		}
-
-	};
-=====*/
-
-	"use strict";
-	function advise(dispatcher, type, advice, receiveArguments){
-		var previous = dispatcher[type];
-		var around = type == "around";
-		var signal;
-		if(around){
-			var advised = advice(function(){
-				return previous.advice(this, arguments);
-			});
-			signal = {
-				remove: function(){
-					signal.cancelled = true;
-				},
-				advice: function(target, args){
-					return signal.cancelled ?
-						previous.advice(target, args) : // cancelled, skip to next one
-						advised.apply(target, args);	// called the advised function
-				}
-			};
-		}else{
-			// create the remove handler
-			signal = {
-				remove: function(){
-					var previous = signal.previous;
-					var next = signal.next;
-					if(!next && !previous){
-						delete dispatcher[type];
-					}else{
-						if(previous){
-							previous.next = next;
-						}else{
-							dispatcher[type] = next;
-						}
-						if(next){
-							next.previous = previous;
-						}
-					}
-				},
-				advice: advice,
-				receiveArguments: receiveArguments
-			};
-		}
-		if(previous && !around){
-			if(type == "after"){
-				// add the listener to the end of the list
-				var next = previous;
-				while(next){
-					previous = next;
-					next = next.next;
-				}
-				previous.next = signal;
-				signal.previous = previous;
-			}else if(type == "before"){
-				// add to beginning
-				dispatcher[type] = signal;
-				signal.next = previous;
-				previous.previous = signal;
-			}
-		}else{
-			// around or first one just replaces
-			dispatcher[type] = signal;
-		}
-		return signal;
-	}
-	function aspect(type){
-		return function(target, methodName, advice, receiveArguments){
-			var existing = target[methodName], dispatcher;
-			if(!existing || existing.target != target){
-				// no dispatcher in place
-				dispatcher = target[methodName] = function(){
-					// before advice
-					var args = arguments;
-					var before = dispatcher.before;
-					while(before){
-						args = before.advice.apply(this, args) || args;
-						before = before.next;
-					}
-					// around advice
-					if(dispatcher.around){
-						var results = dispatcher.around.advice(this, args);
-					}
-					// after advice
-					var after = dispatcher.after;
-					while(after){
-						results = after.receiveArguments ? after.advice.apply(this, args) || results :
-								after.advice.call(this, results);
-						after = after.next;
-					}
-					return results;
-				};
-				if(existing){
-					dispatcher.around = {advice: function(target, args){
-						return existing.apply(target, args);
-					}};
-				}
-				dispatcher.target = target;
-			}
-			var results = advise((dispatcher || existing), type, advice, receiveArguments);
-			advice = null;
-			return results;
-		};
-	}
-	return {
-		before: aspect("before"),
-		around: aspect("around"),
-		after: aspect("after")
-	};
-});
+define([], function(){
+
+// TODOC: after/before/around return object
+// TODOC: after/before/around param types. 
+
+/*=====
+	dojo.aspect = {
+		// summary: provides aspect oriented programming functionality, allowing for
+		//		one to add before, around, or after advice on existing methods.
+		//
+		// example:
+		//	|	define(["dojo/aspect"], function(aspect){
+		//	|		var signal = aspect.after(targetObject, "methodName", function(someArgument){
+		//	|			this will be called when targetObject.methodName() is called, after the original function is called
+		//	|		});
+		//
+		// example:
+		//	The returned signal object can be used to cancel the advice.
+		//	|	signal.remove(); // this will stop the advice from being executed anymore
+		//	|	aspect.before(targetObject, "methodName", function(someArgument){
+		//	|		// this will be called when targetObject.methodName() is called, before the original function is called
+		//	|	 });
+		
+		after: function(target, methodName, advice, receiveArguments){
+			// summary: The "after" export of the aspect module is a function that can be used to attach
+			//		"after" advice to a method. This function will be executed after the original method
+			//		is executed. By default the function will be called with a single argument, the return
+			//		value of the original method, or the the return value of the last executed advice (if a previous one exists).
+			//		The fourth (optional) argument can be set to true to so the function receives the original
+			//		arguments (from when the original method was called) rather than the return value.
+			//		If there are multiple "after" advisors, they are executed in the order they were registered.
+			// target: Object
+			//		This is the target object
+			// methodName: String
+			//		This is the name of the method to attach to.
+			// advice: Function
+			//		This is function to be called after the original method
+			// receiveArguments: Boolean?
+			//		If this is set to true, the advice function receives the original arguments (from when the original mehtod
+			//		was called) rather than the return value of the original/previous method.
+			// returns:
+			//		A signal object that can be used to cancel the advice. If remove() is called on this signal object, it will
+			//		stop the advice function from being executed.
+		},
+		
+		before: function(target, methodName, advice){
+			// summary: The "before" export of the aspect module is a function that can be used to attach
+			//		"before" advice to a method. This function will be executed before the original method
+			//		is executed. This function will be called with the arguments used to call the method.
+			//		This function may optionally return an array as the new arguments to use to call
+			//		the original method (or the previous, next-to-execute before advice, if one exists).
+			//		If the before method doesn't return anything (returns undefined) the original arguments
+			//		will be preserved.
+			//		If there are multiple "before" advisors, they are executed in the reverse order they were registered.
+			//
+			// target: Object
+			//		This is the target object
+			// methodName: String
+			//		This is the name of the method to attach to.
+			// advice: Function
+			//		This is function to be called before the original method	 
+		},
+
+		around: function(target, methodName, advice){
+			// summary: The "around" export of the aspect module is a function that can be used to attach
+			//		"around" advice to a method. The advisor function is immediately executed when
+			//		the around() is called, is passed a single argument that is a function that can be
+			//		called to continue execution of the original method (or the next around advisor).
+			//		The advisor function should return a function, and this function will be called whenever
+			//		the method is called. It will be called with the arguments used to call the method.
+			//		Whatever this function returns will be returned as the result of the method call (unless after advise changes it).
+			//
+			// example:
+			//		If there are multiple "around" advisors, the most recent one is executed first,
+			//		which can then delegate to the next one and so on. For example:
+			//		|	around(obj, "foo", function(originalFoo){
+			//		|		return function(){
+			//		|			var start = new Date().getTime();
+			//		|			var results = originalFoo.apply(this, arguments); // call the original
+			//		|			var end = new Date().getTime();
+			//		|			console.log("foo execution took " + (end - start) + " ms");
+			//		|			return results;
+			//		|		};
+			//		|	});
+			//
+			// target: Object
+			//		This is the target object
+			// methodName: String
+			//		This is the name of the method to attach to.
+			// advice: Function
+			//		This is function to be called around the original method
+		}
+
+	};
+=====*/
+
+	"use strict";
+	function advise(dispatcher, type, advice, receiveArguments){
+		var previous = dispatcher[type];
+		var around = type == "around";
+		var signal;
+		if(around){
+			var advised = advice(function(){
+				return previous.advice(this, arguments);
+			});
+			signal = {
+				remove: function(){
+					signal.cancelled = true;
+				},
+				advice: function(target, args){
+					return signal.cancelled ?
+						previous.advice(target, args) : // cancelled, skip to next one
+						advised.apply(target, args);	// called the advised function
+				}
+			};
+		}else{
+			// create the remove handler
+			signal = {
+				remove: function(){
+					var previous = signal.previous;
+					var next = signal.next;
+					if(!next && !previous){
+						delete dispatcher[type];
+					}else{
+						if(previous){
+							previous.next = next;
+						}else{
+							dispatcher[type] = next;
+						}
+						if(next){
+							next.previous = previous;
+						}
+					}
+				},
+				advice: advice,
+				receiveArguments: receiveArguments
+			};
+		}
+		if(previous && !around){
+			if(type == "after"){
+				// add the listener to the end of the list
+				var next = previous;
+				while(next){
+					previous = next;
+					next = next.next;
+				}
+				previous.next = signal;
+				signal.previous = previous;
+			}else if(type == "before"){
+				// add to beginning
+				dispatcher[type] = signal;
+				signal.next = previous;
+				previous.previous = signal;
+			}
+		}else{
+			// around or first one just replaces
+			dispatcher[type] = signal;
+		}
+		return signal;
+	}
+	function aspect(type){
+		return function(target, methodName, advice, receiveArguments){
+			var existing = target[methodName], dispatcher;
+			if(!existing || existing.target != target){
+				// no dispatcher in place
+				dispatcher = target[methodName] = function(){
+					// before advice
+					var args = arguments;
+					var before = dispatcher.before;
+					while(before){
+						args = before.advice.apply(this, args) || args;
+						before = before.next;
+					}
+					// around advice
+					if(dispatcher.around){
+						var results = dispatcher.around.advice(this, args);
+					}
+					// after advice
+					var after = dispatcher.after;
+					while(after){
+						results = after.receiveArguments ? after.advice.apply(this, args) || results :
+								after.advice.call(this, results);
+						after = after.next;
+					}
+					return results;
+				};
+				if(existing){
+					dispatcher.around = {advice: function(target, args){
+						return existing.apply(target, args);
+					}};
+				}
+				dispatcher.target = target;
+			}
+			var results = advise((dispatcher || existing), type, advice, receiveArguments);
+			advice = null;
+			return results;
+		};
+	}
+	return {
+		before: aspect("before"),
+		around: aspect("around"),
+		after: aspect("after")
+	};
+});
diff --git a/json.js b/json.js
index 798a4c6..b975b29 100644
--- a/json.js
+++ b/json.js
@@ -1,149 +1,149 @@
-define(["./has"], function(has){
-	"use strict";
-	var hasJSON = typeof JSON != "undefined";
-	has.add("json-parse", hasJSON); // all the parsers work fine
-		// Firefox 3.5/Gecko 1.9 fails to use replacer in stringify properly https://bugzilla.mozilla.org/show_bug.cgi?id=509184
-	has.add("json-stringify", hasJSON && JSON.stringify({a:0}, function(k,v){return v||1;}) == '{"a":1}'); 
-	if(has("json-stringify")){
-		return JSON;
-	}
-	else{
-		var escapeString = function(/*String*/str){
-			//summary:
-			//		Adds escape sequences for non-visual characters, double quote and
-			//		backslash and surrounds with double quotes to form a valid string
-			//		literal.
-			return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
-				replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
-				replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
-		};
-		return {
-			parse: has("json-parse") ? JSON.parse : function(str, strict){
-				// summary:
-				// 		Parses a [JSON](http://json.org) string to return a JavaScript object.
-				// description:
-				//		This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
-				// 		Throws for invalid JSON strings. This delegates to eval() if native JSON
-				// 		support is not available. By default this will evaluate any valid JS expression.
-				//		With the strict parameter set to true, the parser will ensure that only
-				//		valid JSON strings are parsed (otherwise throwing an error). Without the strict
-				// 		parameter, the content passed to this method must come
-				//		from a trusted source.
-				// str:
-				//		a string literal of a JSON item, for instance:
-				//			`'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
-				//	strict: 
-				//		When set to true, this will ensure that only valid, secure JSON is ever parsed.
-				// 		Make sure this is set to true for untrusted content. Note that on browsers/engines
-				//		without native JSON support, setting this to true will run slower.
-				if(strict && !/^([\s\[\{]*(?:"(?:\\.|[^"])+"|-?\d[\d\.]*(?:[Ee][+-]?\d+)?|null|true|false|)[\s\]\}]*(?:,|:|$))+$/.test(str)){
-					throw new SyntaxError("Invalid characters in JSON");
-				}
-				return eval('(' + str + ')');
-			},
-			stringify: function(value, replacer, spacer){
-				//	summary:
-				//		Returns a [JSON](http://json.org) serialization of an object.
-				//	description:
-				//		Returns a [JSON](http://json.org) serialization of an object.
-				//		This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
-				//		Note that this doesn't check for infinite recursion, so don't do that!
-				//	value:
-				//		A value to be serialized. 
-				//	replacer:
-				//		A replacer function that is called for each value and can return a replacement
-				//	spacer:
-				//		A spacer string to be used for pretty printing of JSON
-				//		
-				//	example:
-				//		simple serialization of a trivial object
-				//		|	define(["dojo/json"], function(JSON){
-				// 		|		var jsonStr = JSON.stringify({ howdy: "stranger!", isStrange: true });
-				//		|		doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
-				var undef;
-				if(typeof replacer == "string"){
-					spacer = replacer;
-					replacer = null;
-				}
-				function stringify(it, indent, key){
-					if(replacer){
-						it = replacer(key, it);
-					}
-					var val, objtype = typeof it;
-					if(objtype == "number"){
-						return isFinite(it) ? it + "" : "null";
-					}
-					if(objtype == "boolean"){
-						return it + "";
-					}
-					if(it === null){
-						return "null";
-					}
-					if(typeof it == "string"){
-						return escapeString(it);
-					}
-					if(objtype == "function" || objtype == "undefined"){
-						return undef; // undefined
-					}
-					// short-circuit for objects that support "json" serialization
-					// if they return "self" then just pass-through...
-					if(typeof it.toJSON == "function"){
-						return stringify(it.toJSON(key), indent, key);
-					}
-					if(it instanceof Date){
-						return '"{FullYear}-{Month+}-{Date}T{Hours}:{Minutes}:{Seconds}Z"'.replace(/\{(\w+)(\+)?\}/g, function(t, prop, plus){
-							var num = it["getUTC" + prop]() + (plus ? 1 : 0);
-							return num < 10 ? "0" + num : num;
-						});
-					}
-					if(it.valueOf() !== it){
-						// primitive wrapper, try again unwrapped:
-						return stringify(it.valueOf(), indent, key);
-					}
-					var nextIndent= spacer ? (indent + spacer) : "";
-					/* we used to test for DOM nodes and throw, but FF serializes them as {}, so cross-browser consistency is probably not efficiently attainable */ 
-				
-					var sep = spacer ? " " : "";
-					var newLine = spacer ? "\n" : "";
-				
-					// array
-					if(it instanceof Array){
-						var itl = it.length, res = [];
-						for(key = 0; key < itl; key++){
-							var obj = it[key];
-							val = stringify(obj, nextIndent, key);
-							if(typeof val != "string"){
-								val = "null";
-							}
-							res.push(newLine + nextIndent + val);
-						}
-						return "[" + res.join(",") + newLine + indent + "]";
-					}
-					// generic object code path
-					var output = [];
-					for(key in it){
-						var keyStr;
-						if(typeof key == "number"){
-							keyStr = '"' + key + '"';
-						}else if(typeof key == "string"){
-							keyStr = escapeString(key);
-						}else{
-							// skip non-string or number keys
-							continue;
-						}
-						val = stringify(it[key], nextIndent, key);
-						if(typeof val != "string"){
-							// skip non-serializable values
-							continue;
-						}
-						// At this point, the most non-IE browsers don't get in this branch 
-						// (they have native JSON), so push is definitely the way to
-						output.push(newLine + nextIndent + keyStr + ":" + sep + val);
-					}
-					return "{" + output.join(",") + newLine + indent + "}"; // String
-				}
-				return stringify(value, "", "");
-			}
-		};
-	}
-});
+define(["./has"], function(has){
+	"use strict";
+	var hasJSON = typeof JSON != "undefined";
+	has.add("json-parse", hasJSON); // all the parsers work fine
+		// Firefox 3.5/Gecko 1.9 fails to use replacer in stringify properly https://bugzilla.mozilla.org/show_bug.cgi?id=509184
+	has.add("json-stringify", hasJSON && JSON.stringify({a:0}, function(k,v){return v||1;}) == '{"a":1}'); 
+	if(has("json-stringify")){
+		return JSON;
+	}
+	else{
+		var escapeString = function(/*String*/str){
+			//summary:
+			//		Adds escape sequences for non-visual characters, double quote and
+			//		backslash and surrounds with double quotes to form a valid string
+			//		literal.
+			return ('"' + str.replace(/(["\\])/g, '\\$1') + '"').
+				replace(/[\f]/g, "\\f").replace(/[\b]/g, "\\b").replace(/[\n]/g, "\\n").
+				replace(/[\t]/g, "\\t").replace(/[\r]/g, "\\r"); // string
+		};
+		return {
+			parse: has("json-parse") ? JSON.parse : function(str, strict){
+				// summary:
+				// 		Parses a [JSON](http://json.org) string to return a JavaScript object.
+				// description:
+				//		This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
+				// 		Throws for invalid JSON strings. This delegates to eval() if native JSON
+				// 		support is not available. By default this will evaluate any valid JS expression.
+				//		With the strict parameter set to true, the parser will ensure that only
+				//		valid JSON strings are parsed (otherwise throwing an error). Without the strict
+				// 		parameter, the content passed to this method must come
+				//		from a trusted source.
+				// str:
+				//		a string literal of a JSON item, for instance:
+				//			`'{ "foo": [ "bar", 1, { "baz": "thud" } ] }'`
+				//	strict: 
+				//		When set to true, this will ensure that only valid, secure JSON is ever parsed.
+				// 		Make sure this is set to true for untrusted content. Note that on browsers/engines
+				//		without native JSON support, setting this to true will run slower.
+				if(strict && !/^([\s\[\{]*(?:"(?:\\.|[^"])+"|-?\d[\d\.]*(?:[Ee][+-]?\d+)?|null|true|false|)[\s\]\}]*(?:,|:|$))+$/.test(str)){
+					throw new SyntaxError("Invalid characters in JSON");
+				}
+				return eval('(' + str + ')');
+			},
+			stringify: function(value, replacer, spacer){
+				//	summary:
+				//		Returns a [JSON](http://json.org) serialization of an object.
+				//	description:
+				//		Returns a [JSON](http://json.org) serialization of an object.
+				//		This function follows [native JSON API](https://developer.mozilla.org/en/JSON)
+				//		Note that this doesn't check for infinite recursion, so don't do that!
+				//	value:
+				//		A value to be serialized. 
+				//	replacer:
+				//		A replacer function that is called for each value and can return a replacement
+				//	spacer:
+				//		A spacer string to be used for pretty printing of JSON
+				//		
+				//	example:
+				//		simple serialization of a trivial object
+				//		|	define(["dojo/json"], function(JSON){
+				// 		|		var jsonStr = JSON.stringify({ howdy: "stranger!", isStrange: true });
+				//		|		doh.is('{"howdy":"stranger!","isStrange":true}', jsonStr);
+				var undef;
+				if(typeof replacer == "string"){
+					spacer = replacer;
+					replacer = null;
+				}
+				function stringify(it, indent, key){
+					if(replacer){
+						it = replacer(key, it);
+					}
+					var val, objtype = typeof it;
+					if(objtype == "number"){
+						return isFinite(it) ? it + "" : "null";
+					}
+					if(objtype == "boolean"){
+						return it + "";
+					}
+					if(it === null){
+						return "null";
+					}
+					if(typeof it == "string"){
+						return escapeString(it);
+					}
+					if(objtype == "function" || objtype == "undefined"){
+						return undef; // undefined
+					}
+					// short-circuit for objects that support "json" serialization
+					// if they return "self" then just pass-through...
+					if(typeof it.toJSON == "function"){
+						return stringify(it.toJSON(key), indent, key);
+					}
+					if(it instanceof Date){
+						return '"{FullYear}-{Month+}-{Date}T{Hours}:{Minutes}:{Seconds}Z"'.replace(/\{(\w+)(\+)?\}/g, function(t, prop, plus){
+							var num = it["getUTC" + prop]() + (plus ? 1 : 0);
+							return num < 10 ? "0" + num : num;
+						});
+					}
+					if(it.valueOf() !== it){
+						// primitive wrapper, try again unwrapped:
+						return stringify(it.valueOf(), indent, key);
+					}
+					var nextIndent= spacer ? (indent + spacer) : "";
+					/* we used to test for DOM nodes and throw, but FF serializes them as {}, so cross-browser consistency is probably not efficiently attainable */ 
+				
+					var sep = spacer ? " " : "";
+					var newLine = spacer ? "\n" : "";
+				
+					// array
+					if(it instanceof Array){
+						var itl = it.length, res = [];
+						for(key = 0; key < itl; key++){
+							var obj = it[key];
+							val = stringify(obj, nextIndent, key);
+							if(typeof val != "string"){
+								val = "null";
+							}
+							res.push(newLine + nextIndent + val);
+						}
+						return "[" + res.join(",") + newLine + indent + "]";
+					}
+					// generic object code path
+					var output = [];
+					for(key in it){
+						var keyStr;
+						if(typeof key == "number"){
+							keyStr = '"' + key + '"';
+						}else if(typeof key == "string"){
+							keyStr = escapeString(key);
+						}else{
+							// skip non-string or number keys
+							continue;
+						}
+						val = stringify(it[key], nextIndent, key);
+						if(typeof val != "string"){
+							// skip non-serializable values
+							continue;
+						}
+						// At this point, the most non-IE browsers don't get in this branch 
+						// (they have native JSON), so push is definitely the way to
+						output.push(newLine + nextIndent + keyStr + ":" + sep + val);
+					}
+					return "{" + output.join(",") + newLine + indent + "}"; // String
+				}
+				return stringify(value, "", "");
+			}
+		};
+	}
+});
diff --git a/keys.js b/keys.js
index d2bfc00..3347e74 100644
--- a/keys.js
+++ b/keys.js
@@ -1,80 +1,80 @@
-define(["./_base/kernel", "./_base/sniff"], function(dojo, has) {
-	// module:
-	//		dojo/keys
-	// summary:
-	//		key constants
-// Constants
-
-// Public: client code should test
-// keyCode against these named constants, as the
-// actual codes can vary by browser.
-return dojo.keys = {
-	// summary:
-	//		Definitions for common key values
-	BACKSPACE: 8,
-	TAB: 9,
-	CLEAR: 12,
-	ENTER: 13,
-	SHIFT: 16,
-	CTRL: 17,
-	ALT: 18,
-	META: has("safari") ? 91 : 224,		// the apple key on macs
-	PAUSE: 19,
-	CAPS_LOCK: 20,
-	ESCAPE: 27,
-	SPACE: 32,
-	PAGE_UP: 33,
-	PAGE_DOWN: 34,
-	END: 35,
-	HOME: 36,
-	LEFT_ARROW: 37,
-	UP_ARROW: 38,
-	RIGHT_ARROW: 39,
-	DOWN_ARROW: 40,
-	INSERT: 45,
-	DELETE: 46,
-	HELP: 47,
-	LEFT_WINDOW: 91,
-	RIGHT_WINDOW: 92,
-	SELECT: 93,
-	NUMPAD_0: 96,
-	NUMPAD_1: 97,
-	NUMPAD_2: 98,
-	NUMPAD_3: 99,
-	NUMPAD_4: 100,
-	NUMPAD_5: 101,
-	NUMPAD_6: 102,
-	NUMPAD_7: 103,
-	NUMPAD_8: 104,
-	NUMPAD_9: 105,
-	NUMPAD_MULTIPLY: 106,
-	NUMPAD_PLUS: 107,
-	NUMPAD_ENTER: 108,
-	NUMPAD_MINUS: 109,
-	NUMPAD_PERIOD: 110,
-	NUMPAD_DIVIDE: 111,
-	F1: 112,
-	F2: 113,
-	F3: 114,
-	F4: 115,
-	F5: 116,
-	F6: 117,
-	F7: 118,
-	F8: 119,
-	F9: 120,
-	F10: 121,
-	F11: 122,
-	F12: 123,
-	F13: 124,
-	F14: 125,
-	F15: 126,
-	NUM_LOCK: 144,
-	SCROLL_LOCK: 145,
-	UP_DPAD: 175,
-	DOWN_DPAD: 176,
-	LEFT_DPAD: 177,
-	RIGHT_DPAD: 178,
-	// virtual key mapping
-	copyKey: has("mac") && !has("air") ? (has("safari") ? 91 : 224 ) : 17
-};
-});
+define(["./_base/kernel", "./_base/sniff"], function(dojo, has) {
+	// module:
+	//		dojo/keys
+	// summary:
+	//		key constants
+// Constants
+
+// Public: client code should test
+// keyCode against these named constants, as the
+// actual codes can vary by browser.
+return dojo.keys = {
+	// summary:
+	//		Definitions for common key values
+	BACKSPACE: 8,
+	TAB: 9,
+	CLEAR: 12,
+	ENTER: 13,
+	SHIFT: 16,
+	CTRL: 17,
+	ALT: 18,
+	META: has("safari") ? 91 : 224,		// the apple key on macs
+	PAUSE: 19,
+	CAPS_LOCK: 20,
+	ESCAPE: 27,
+	SPACE: 32,
+	PAGE_UP: 33,
+	PAGE_DOWN: 34,
+	END: 35,
+	HOME: 36,
+	LEFT_ARROW: 37,
+	UP_ARROW: 38,
+	RIGHT_ARROW: 39,
+	DOWN_ARROW: 40,
+	INSERT: 45,
+	DELETE: 46,
+	HELP: 47,
+	LEFT_WINDOW: 91,
+	RIGHT_WINDOW: 92,
+	SELECT: 93,
+	NUMPAD_0: 96,
+	NUMPAD_1: 97,
+	NUMPAD_2: 98,
+	NUMPAD_3: 99,
+	NUMPAD_4: 100,
+	NUMPAD_5: 101,
+	NUMPAD_6: 102,
+	NUMPAD_7: 103,
+	NUMPAD_8: 104,
+	NUMPAD_9: 105,
+	NUMPAD_MULTIPLY: 106,
+	NUMPAD_PLUS: 107,
+	NUMPAD_ENTER: 108,
+	NUMPAD_MINUS: 109,
+	NUMPAD_PERIOD: 110,
+	NUMPAD_DIVIDE: 111,
+	F1: 112,
+	F2: 113,
+	F3: 114,
+	F4: 115,
+	F5: 116,
+	F6: 117,
+	F7: 118,
+	F8: 119,
+	F9: 120,
+	F10: 121,
+	F11: 122,
+	F12: 123,
+	F13: 124,
+	F14: 125,
+	F15: 126,
+	NUM_LOCK: 144,
+	SCROLL_LOCK: 145,
+	UP_DPAD: 175,
+	DOWN_DPAD: 176,
+	LEFT_DPAD: 177,
+	RIGHT_DPAD: 178,
+	// virtual key mapping
+	copyKey: has("mac") && !has("air") ? (has("safari") ? 91 : 224 ) : 17
+};
+});
diff --git a/mouse.js b/mouse.js
index 48a0f86..9d47f82 100644
--- a/mouse.js
+++ b/mouse.js
@@ -1,127 +1,127 @@
-define(["./_base/kernel", "./on", "./has", "./dom", "./_base/window"], function(dojo, on, has, dom, win){
-
-	/*=====
-	dojo.mouse = {
-	// summary:
-	//		This module provide mouse event handling utility functions and exports
-	//		mouseenter and mouseleave event emulation.
-	// enter: Synthetic Event
-	//		This is an extension event for the mouseenter that IE provides, emulating the
-	//		behavior on other browsers.
-	// leave: Synthetic Event
-	//		This is an extension event for the mouseleave that IE provides, emulating the
-	//		behavior on other browsers.
-	// isLeft: Function
-	//		Test an event object (from a mousedown event) to see if the left button was pressed.
-	// isMiddle: Function
-	//		Test an event object (from a mousedown event) to see if the middle button was pressed.
-	// isRight: Function
-	//		Test an event object (from a mousedown event) to see if the right button was pressed.
-	// example:
-	//		To use these events, you register a mouseenter like this:
-	//		|	define(["dojo/on", dojo/mouse"], function(on, mouse){
-	//		|		on(targetNode, mouse.enter, function(event){
-	//		|			dojo.addClass(targetNode, "highlighted");
-	//		|		});
-	//		|		on(targetNode, mouse.leave, function(event){
-	//		|			dojo.removeClass(targetNode, "highlighted");
-	//		|		});
-	};
-	======*/
-
-    has.add("dom-quirks", win.doc && win.doc.compatMode == "BackCompat");
- 	has.add("events-mouseenter", win.doc && "onmouseenter" in win.doc.createElement("div"));
-
-	var mouseButtons;
-	if(has("dom-quirks") || !has("dom-addeventlistener")){
-		mouseButtons = {
-			LEFT:   1,
-			MIDDLE: 4,
-			RIGHT:  2,
-			// helper functions
-			isButton: function(e, button){ return e.button & button; },
-			isLeft:   function(e){ return e.button & 1; },
-			isMiddle: function(e){ return e.button & 4; },
-			isRight:  function(e){ return e.button & 2; }
-		};
-	}else{
-		mouseButtons = {
-			LEFT:   0,
-			MIDDLE: 1,
-			RIGHT:  2,
-			// helper functions
-			isButton: function(e, button){ return e.button == button; },
-			isLeft:   function(e){ return e.button == 0; },
-			isMiddle: function(e){ return e.button == 1; },
-			isRight:  function(e){ return e.button == 2; }
-		};
-	}
-	dojo.mouseButtons = mouseButtons;
-
-/*=====
-	dojo.mouseButtons = {
-		// LEFT: Number
-		//		Numeric value of the left mouse button for the platform.
-		LEFT:   0,
-		// MIDDLE: Number
-		//		Numeric value of the middle mouse button for the platform.
-		MIDDLE: 1,
-		// RIGHT: Number
-		//		Numeric value of the right mouse button for the platform.
-		RIGHT:  2,
-
-		isButton: function(e, button){
-			// summary:
-			//		Checks an event object for a pressed button
-			// e: Event
-			//		Event object to examine
-			// button: Number
-			//		The button value (example: dojo.mouseButton.LEFT)
-			return e.button == button; // Boolean
-		},
-		isLeft: function(e){
-			// summary:
-			//		Checks an event object for the pressed left button
-			// e: Event
-			//		Event object to examine
-			return e.button == 0; // Boolean
-		},
-		isMiddle: function(e){
-			// summary:
-			//		Checks an event object for the pressed middle button
-			// e: Event
-			//		Event object to examine
-			return e.button == 1; // Boolean
-		},
-		isRight: function(e){
-			// summary:
-			//		Checks an event object for the pressed right button
-			// e: Event
-			//		Event object to examine
-			return e.button == 2; // Boolean
-		}
-	};
-=====*/
-
-	function eventHandler(type, mustBubble){
-		// emulation of mouseenter/leave with mouseover/out using descendant checking
-		var handler = function(node, listener){
-			return on(node, type, function(evt){
-				if(!dom.isDescendant(evt.relatedTarget, mustBubble ? evt.target : node)){
-					return listener.call(this, evt);
-				}
-			});
-		};
-		if(!mustBubble){
-			handler.bubble = eventHandler(type, true);
-		}
-		return handler;
-	}
-	return {
-		enter: eventHandler("mouseover"),
-		leave: eventHandler("mouseout"),
-		isLeft: mouseButtons.isLeft,
-		isMiddle: mouseButtons.isMiddle,
-		isRight: mouseButtons.isRight
-	};
-});
+define(["./_base/kernel", "./on", "./has", "./dom", "./_base/window"], function(dojo, on, has, dom, win){
+
+	/*=====
+	dojo.mouse = {
+	// summary:
+	//		This module provide mouse event handling utility functions and exports
+	//		mouseenter and mouseleave event emulation.
+	// enter: Synthetic Event
+	//		This is an extension event for the mouseenter that IE provides, emulating the
+	//		behavior on other browsers.
+	// leave: Synthetic Event
+	//		This is an extension event for the mouseleave that IE provides, emulating the
+	//		behavior on other browsers.
+	// isLeft: Function
+	//		Test an event object (from a mousedown event) to see if the left button was pressed.
+	// isMiddle: Function
+	//		Test an event object (from a mousedown event) to see if the middle button was pressed.
+	// isRight: Function
+	//		Test an event object (from a mousedown event) to see if the right button was pressed.
+	// example:
+	//		To use these events, you register a mouseenter like this:
+	//		|	define(["dojo/on", dojo/mouse"], function(on, mouse){
+	//		|		on(targetNode, mouse.enter, function(event){
+	//		|			dojo.addClass(targetNode, "highlighted");
+	//		|		});
+	//		|		on(targetNode, mouse.leave, function(event){
+	//		|			dojo.removeClass(targetNode, "highlighted");
+	//		|		});
+	};
+	======*/
+
+    has.add("dom-quirks", win.doc && win.doc.compatMode == "BackCompat");
+ 	has.add("events-mouseenter", win.doc && "onmouseenter" in win.doc.createElement("div"));
+
+	var mouseButtons;
+	if(has("dom-quirks") || !has("dom-addeventlistener")){
+		mouseButtons = {
+			LEFT:   1,
+			MIDDLE: 4,
+			RIGHT:  2,
+			// helper functions
+			isButton: function(e, button){ return e.button & button; },
+			isLeft:   function(e){ return e.button & 1; },
+			isMiddle: function(e){ return e.button & 4; },
+			isRight:  function(e){ return e.button & 2; }
+		};
+	}else{
+		mouseButtons = {
+			LEFT:   0,
+			MIDDLE: 1,
+			RIGHT:  2,
+			// helper functions
+			isButton: function(e, button){ return e.button == button; },
+			isLeft:   function(e){ return e.button == 0; },
+			isMiddle: function(e){ return e.button == 1; },
+			isRight:  function(e){ return e.button == 2; }
+		};
+	}
+	dojo.mouseButtons = mouseButtons;
+
+/*=====
+	dojo.mouseButtons = {
+		// LEFT: Number
+		//		Numeric value of the left mouse button for the platform.
+		LEFT:   0,
+		// MIDDLE: Number
+		//		Numeric value of the middle mouse button for the platform.
+		MIDDLE: 1,
+		// RIGHT: Number
+		//		Numeric value of the right mouse button for the platform.
+		RIGHT:  2,
+
+		isButton: function(e, button){
+			// summary:
+			//		Checks an event object for a pressed button
+			// e: Event
+			//		Event object to examine
+			// button: Number
+			//		The button value (example: dojo.mouseButton.LEFT)
+			return e.button == button; // Boolean
+		},
+		isLeft: function(e){
+			// summary:
+			//		Checks an event object for the pressed left button
+			// e: Event
+			//		Event object to examine
+			return e.button == 0; // Boolean
+		},
+		isMiddle: function(e){
+			// summary:
+			//		Checks an event object for the pressed middle button
+			// e: Event
+			//		Event object to examine
+			return e.button == 1; // Boolean
+		},
+		isRight: function(e){
+			// summary:
+			//		Checks an event object for the pressed right button
+			// e: Event
+			//		Event object to examine
+			return e.button == 2; // Boolean
+		}
+	};
+=====*/
+
+	function eventHandler(type, mustBubble){
+		// emulation of mouseenter/leave with mouseover/out using descendant checking
+		var handler = function(node, listener){
+			return on(node, type, function(evt){
+				if(!dom.isDescendant(evt.relatedTarget, mustBubble ? evt.target : node)){
+					return listener.call(this, evt);
+				}
+			});
+		};
+		if(!mustBubble){
+			handler.bubble = eventHandler(type, true);
+		}
+		return handler;
+	}
+	return {
+		enter: eventHandler("mouseover"),
+		leave: eventHandler("mouseout"),
+		isLeft: mouseButtons.isLeft,
+		isMiddle: mouseButtons.isMiddle,
+		isRight: mouseButtons.isRight
+	};
+});
diff --git a/on.js b/on.js
index 08880c9..dcc0613 100644
--- a/on.js
+++ b/on.js
@@ -1,473 +1,473 @@
-define(["./has!dom-addeventlistener?:./aspect", "./_base/kernel", "./has"], function(aspect, dojo, has){
-	// summary:
-	//		The export of this module is a function that provides core event listening functionality. With this function
-	//		you can provide a target, event type, and listener to be notified of
-	//		future matching events that are fired.
-	// target: Element|Object
-	//		This is the target object or DOM element that to receive events from
-	// type: String|Function
-	// 		This is the name of the event to listen for or an extension event type.
-	// listener: Function
-	// 		This is the function that should be called when the event fires.
-	// returns: Object
-	// 		An object with a remove() method that can be used to stop listening for this
-	// 		event.
-	// description:
-	// 		To listen for "click" events on a button node, we can do:
-	// 		|	define(["dojo/on"], function(listen){
-	// 		|		on(button, "click", clickHandler);
-	//		|		...
-	//  	Evented JavaScript objects can also have their own events.
-	// 		|	var obj = new Evented;
-	//		|	on(obj, "foo", fooHandler);
-	//		And then we could publish a "foo" event:
-	//		|	on.emit(obj, "foo", {key: "value"});
-	//		We can use extension events as well. For example, you could listen for a tap gesture:
-	// 		|	define(["dojo/on", "dojo/gesture/tap", function(listen, tap){
-	// 		|		on(button, tap, tapHandler);
-	//		|		...
-	//		which would trigger fooHandler. Note that for a simple object this is equivalent to calling:
-	//		|	obj.onfoo({key:"value"});
-	//		If you use on.emit on a DOM node, it will use native event dispatching when possible.
-
- 	"use strict";
-	if(has("dom")){ // check to make sure we are in a browser, this module should work anywhere
-		var major = window.ScriptEngineMajorVersion;
-		has.add("jscript", major && (major() + ScriptEngineMinorVersion() / 10));
-		has.add("event-orientationchange", has("touch") && !has("android")); // TODO: how do we detect this?
-	}
-	var on = function(target, type, listener, dontFix){
-		if(target.on){ 
-			// delegate to the target's on() method, so it can handle it's own listening if it wants
-			return target.on(type, listener);
-		}
-		// delegate to main listener code
-		return on.parse(target, type, listener, addListener, dontFix, this);
-	};
-	on.pausable =  function(target, type, listener, dontFix){
-		// summary:
-		//		This function acts the same as on(), but with pausable functionality. The
-		// 		returned signal object has pause() and resume() functions. Calling the
-		//		pause() method will cause the listener to not be called for future events. Calling the
-		//		resume() method will cause the listener to again be called for future events.
-		var paused;
-		var signal = on(target, type, function(){
-			if(!paused){
-				return listener.apply(this, arguments);
-			}
-		}, dontFix);
-		signal.pause = function(){
-			paused = true;
-		};
-		signal.resume = function(){
-			paused = false;
-		};
-		return signal;
-	};
-	on.once = function(target, type, listener, dontFix){
-		// summary:
-		//		This function acts the same as on(), but will only call the listener once. The 
-		// 		listener will be called for the first
-		//		event that takes place and then listener will automatically be removed.
-		var signal = on(target, type, function(){
-			// remove this listener
-			signal.remove();
-			// proceed to call the listener
-			return listener.apply(this, arguments);
-		});
-		return signal;
-	};
-	on.parse = function(target, type, listener, addListener, dontFix, matchesTarget){
-		if(type.call){
-			// event handler function
-			// on(node, dojo.touch.press, touchListener);
-			return type.call(matchesTarget, target, listener);
-		}
-
-		if(type.indexOf(",") > -1){
-			// we allow comma delimited event names, so you can register for multiple events at once
-			var events = type.split(/\s*,\s*/);
-			var handles = [];
-			var i = 0;
-			var eventName;
-			while(eventName = events[i++]){
-				handles.push(addListener(target, eventName, listener, dontFix, matchesTarget));
-			}
-			handles.remove = function(){
-				for(var i = 0; i < handles.length; i++){
-					handles[i].remove();
-				}
-			};
-			return handles;
-		}
-		return addListener(target, type, listener, dontFix, matchesTarget)
-	};
-	var touchEvents = /^touch/;
-	function addListener(target, type, listener, dontFix, matchesTarget){		
-		// event delegation:
-		var selector = type.match(/(.*):(.*)/);
-		// if we have a selector:event, the last one is interpreted as an event, and we use event delegation
-		if(selector){
-			type = selector[2];
-			selector = selector[1];
-			// create the extension event for selectors and directly call it
-			return on.selector(selector, type).call(matchesTarget, target, listener);
-		}
-		// test to see if it a touch event right now, so we don't have to do it every time it fires
-		if(has("touch")){
-			if(touchEvents.test(type)){
-				// touch event, fix it
-				listener = fixTouchListener(listener);
-			}
-			if(!has("event-orientationchange") && (type == "orientationchange")){
-				//"orientationchange" not supported <= Android 2.1, 
-				//but works through "resize" on window
-				type = "resize"; 
-				target = window;
-				listener = fixTouchListener(listener);
-			} 
-		}
-		// normal path, the target is |this|
-		if(target.addEventListener){
-			// the target has addEventListener, which should be used if available (might or might not be a node, non-nodes can implement this method as well)
-			// check for capture conversions
-			var capture = type in captures;
-			target.addEventListener(capture ? captures[type] : type, listener, capture);
-			// create and return the signal
-			return {
-				remove: function(){
-					target.removeEventListener(type, listener, capture);
-				}
-			};
-		}
-		type = "on" + type;
-		if(fixAttach && target.attachEvent){
-			return fixAttach(target, type, listener);
-		}
-	 	throw new Error("Target must be an event emitter");
-	}
-
-	on.selector = function(selector, eventType, children){
-		// summary:
-		//		Creates a new extension event with event delegation. This is based on
-		// 		the provided event type (can be extension event) that
-		// 		only calls the listener when the CSS selector matches the target of the event.
-		//	selector:
-		//		The CSS selector to use for filter events and determine the |this| of the event listener.
-		//	eventType:
-		//		The event to listen for
-		// children:
-		//		Indicates if children elements of the selector should be allowed. This defaults to 
-		// 		true (except in the case of normally non-bubbling events like mouse.enter, in which case it defaults to false).
-		//	example:
-		//		define(["dojo/on", "dojo/mouse"], function(listen, mouse){
-		//			on(node, on.selector(".my-class", mouse.enter), handlerForMyHover);
-		return function(target, listener){
-			var matchesTarget = this;
-			var bubble = eventType.bubble;
-			if(bubble){
-				// the event type doesn't naturally bubble, but has a bubbling form, use that
-				eventType = bubble;
-			}else if(children !== false){
-				// for normal bubbling events we default to allowing children of the selector
-				children = true;
-			}
-			return on(target, eventType, function(event){
-				var eventTarget = event.target;
-				// see if we have a valid matchesTarget or default to dojo.query
-				matchesTarget = matchesTarget && matchesTarget.matches ? matchesTarget : dojo.query;
-				// there is a selector, so make sure it matches
-				while(!matchesTarget.matches(eventTarget, selector, target)){
-					if(eventTarget == target || !children || !(eventTarget = eventTarget.parentNode)){ // intentional assignment
-						return;
-					}
-				}
-				return listener.call(eventTarget, event);
-			});
-		};
-	};
-
-	function syntheticPreventDefault(){
-		this.cancelable = false;
-	}
-	function syntheticStopPropagation(){
-		this.bubbles = false;
-	}
-	var slice = [].slice,
-		syntheticDispatch = on.emit = function(target, type, event){
-		// summary:
-		//		Fires an event on the target object.
-		//	target:
-		//		The target object to fire the event on. This can be a DOM element or a plain 
-		// 		JS object. If the target is a DOM element, native event emiting mechanisms
-		//		are used when possible.
-		//	type:
-		//		The event type name. You can emulate standard native events like "click" and 
-		// 		"mouseover" or create custom events like "open" or "finish".
-		//	event:
-		//		An object that provides the properties for the event. See https://developer.mozilla.org/en/DOM/event.initEvent 
-		// 		for some of the properties. These properties are copied to the event object.
-		//		Of particular importance are the cancelable and bubbles properties. The
-		//		cancelable property indicates whether or not the event has a default action
-		// 		that can be cancelled. The event is cancelled by calling preventDefault() on
-		// 		the event object. The bubbles property indicates whether or not the
-		//		event will bubble up the DOM tree. If bubbles is true, the event will be called
-		//		on the target and then each parent successively until the top of the tree
-		//		is reached or stopPropagation() is called. Both bubbles and cancelable 
-		// 		default to false.
-		//	returns:
-		//		If the event is cancelable and the event is not cancelled,
-		// 		emit will return true. If the event is cancelable and the event is cancelled,
-		// 		emit will return false.
-		//	details:
-		//		Note that this is designed to emit events for listeners registered through
-		//		dojo/on. It should actually work with any event listener except those
-		// 		added through IE's attachEvent (IE8 and below's non-W3C event emiting
-		// 		doesn't support custom event types). It should work with all events registered
-		// 		through dojo/on. Also note that the emit method does do any default
-		// 		action, it only returns a value to indicate if the default action should take
-		// 		place. For example, emiting a keypress event would not cause a character
-		// 		to appear in a textbox.
-		//	example:
-		//		To fire our own click event
-		//	|	on.emit(dojo.byId("button"), "click", {
-		//	|		cancelable: true,
-		//	|		bubbles: true,
-		//	|		screenX: 33,
-		//	|		screenY: 44
-		//	|	});
-		//		We can also fire our own custom events:
-		//	|	on.emit(dojo.byId("slider"), "slide", {
-		//	|		cancelable: true,
-		//	|		bubbles: true,
-		//	|		direction: "left-to-right"
-		//	|	});
-		var args = slice.call(arguments, 2);
-		var method = "on" + type;
-		if("parentNode" in target){
-			// node (or node-like), create event controller methods
-			var newEvent = args[0] = {};
-			for(var i in event){
-				newEvent[i] = event[i];
-			}
-			newEvent.preventDefault = syntheticPreventDefault;
-			newEvent.stopPropagation = syntheticStopPropagation;
-			newEvent.target = target;
-			newEvent.type = type;
-			event = newEvent;
-		}
-		do{
-			// call any node which has a handler (note that ideally we would try/catch to simulate normal event propagation but that causes too much pain for debugging)
-			target[method] && target[method].apply(target, args);
-			// and then continue up the parent node chain if it is still bubbling (if started as bubbles and stopPropagation hasn't been called)
-		}while(event && event.bubbles && (target = target.parentNode));
-		return event && event.cancelable && event; // if it is still true (was cancelable and was cancelled), return the event to indicate default action should happen
-	};
-	var captures = {}; 
-	if(has("dom-addeventlistener")){
-		// normalize focusin and focusout
-		captures = {
-			focusin: "focus",
-			focusout: "blur"
-		};
-		if(has("opera")){
-			captures.keydown = "keypress"; // this one needs to be transformed because Opera doesn't support repeating keys on keydown (and keypress works because it incorrectly fires on all keydown events)
-		}
-
-		// emiter that works with native event handling
-		on.emit = function(target, type, event){
-			if(target.dispatchEvent && document.createEvent){
-				// use the native event emiting mechanism if it is available on the target object
-				// create a generic event				
-				// we could create branch into the different types of event constructors, but 
-				// that would be a lot of extra code, with little benefit that I can see, seems 
-				// best to use the generic constructor and copy properties over, making it 
-				// easy to have events look like the ones created with specific initializers
-				var nativeEvent = document.createEvent("HTMLEvents");
-				nativeEvent.initEvent(type, !!event.bubbles, !!event.cancelable);
-				// and copy all our properties over
-				for(var i in event){
-					var value = event[i];
-					if(!(i in nativeEvent)){
-						nativeEvent[i] = event[i];
-					}
-				}
-				return target.dispatchEvent(nativeEvent) && nativeEvent;
-			}
-			return syntheticDispatch.apply(on, arguments); // emit for a non-node
-		};
-	}else{
-		// no addEventListener, basically old IE event normalization
-		on._fixEvent = function(evt, sender){
-			// summary:
-			//		normalizes properties on the event object including event
-			//		bubbling methods, keystroke normalization, and x/y positions
-			// evt:
-			//		native event object
-			// sender:
-			//		node to treat as "currentTarget"
-			if(!evt){
-				var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
-				evt = w.event;
-			}
-			if(!evt){return(evt);}
-			if(!evt.target){ // check to see if it has been fixed yet
-				evt.target = evt.srcElement;
-				evt.currentTarget = (sender || evt.srcElement);
-				if(evt.type == "mouseover"){
-					evt.relatedTarget = evt.fromElement;
-				}
-				if(evt.type == "mouseout"){
-					evt.relatedTarget = evt.toElement;
-				}
-				if(!evt.stopPropagation){
-					evt.stopPropagation = stopPropagation;
-					evt.preventDefault = preventDefault;
-				}
-				switch(evt.type){
-					case "keypress":
-						var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
-						if (c==10){
-							// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
-							c=0;
-							evt.keyCode = 13;
-						}else if(c==13||c==27){
-							c=0; // Mozilla considers ENTER and ESC non-printable
-						}else if(c==3){
-							c=99; // Mozilla maps CTRL-BREAK to CTRL-c
-						}
-						// Mozilla sets keyCode to 0 when there is a charCode
-						// but that stops the event on IE.
-						evt.charCode = c;
-						_setKeyChar(evt);
-						break;
-				}
-			}
-			return evt;
-		};
-		var IESignal = function(handle){
-			this.handle = handle;
-		};
-		IESignal.prototype.remove = function(){
-			delete _dojoIEListeners_[this.handle];
-		};
-		var fixListener = function(listener){
-			// this is a minimal function for closing on the previous listener with as few as variables as possible
-			return function(evt){
-				evt = on._fixEvent(evt, this);
-				return listener.call(this, evt);
-			}
-		}
-		var fixAttach = function(target, type, listener){
-			listener = fixListener(listener);
-			if(((target.ownerDocument ? target.ownerDocument.parentWindow : target.parentWindow || target.window || window) != top || 
-						has("jscript") < 5.8) && 
-					!has("config-_allow_leaks")){
-				// IE will leak memory on certain handlers in frames (IE8 and earlier) and in unattached DOM nodes for JScript 5.7 and below.
-				// Here we use global redirection to solve the memory leaks
-				if(typeof _dojoIEListeners_ == "undefined"){
-					_dojoIEListeners_ = [];
-				}
-				var emiter = target[type];
-				if(!emiter || !emiter.listeners){
-					var oldListener = emiter;
-					target[type] = emiter = Function('event', 'var callee = arguments.callee; for(var i = 0; i<callee.listeners.length; i++){var listener = _dojoIEListeners_[callee.listeners[i]]; if(listener){listener.call(this,event);}}');
-					emiter.listeners = [];
-					if(oldListener){
-						emiter.listeners.push(_dojoIEListeners_.push(oldListener) - 1);
-					}
-				}
-				var handle;
-				emiter.listeners.push(handle = (_dojoIEListeners_.push(listener) - 1));
-				return new IESignal(handle);
-			}
-			return aspect.after(target, type, listener, true);
-		};
-
-		var _setKeyChar = function(evt){
-			evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
-			evt.charOrCode = evt.keyChar || evt.keyCode;
-		};
-		// Called in Event scope
-		var stopPropagation = function(){
-			this.cancelBubble = true;
-		};
-		var preventDefault = on._preventDefault = function(){
-			// Setting keyCode to 0 is the only way to prevent certain keypresses (namely
-			// ctrl-combinations that correspond to menu accelerator keys).
-			// Otoh, it prevents upstream listeners from getting this information
-			// Try to split the difference here by clobbering keyCode only for ctrl
-			// combinations. If you still need to access the key upstream, bubbledKeyCode is
-			// provided as a workaround.
-			this.bubbledKeyCode = this.keyCode;
-			if(this.ctrlKey){
-				try{
-					// squelch errors when keyCode is read-only
-					// (e.g. if keyCode is ctrl or shift)
-					this.keyCode = 0;
-				}catch(e){
-				}
-			}
-			this.returnValue = false;
-		};
-	}
-	if(has("touch")){ 
-		var Event = function (){};
-		var windowOrientation = window.orientation; 
-		var fixTouchListener = function(listener){ 
-			return function(originalEvent){ 
-				//Event normalization(for ontouchxxx and resize): 
-				//1.incorrect e.pageX|pageY in iOS 
-				//2.there are no "e.rotation", "e.scale" and "onorientationchange" in Andriod
-				//3.More TBD e.g. force | screenX | screenX | clientX | clientY | radiusX | radiusY
-
-				// see if it has already been corrected
-				var event = originalEvent.corrected;
-				if(!event){
-					var type = originalEvent.type;
-					try{
-						delete originalEvent.type; // on some JS engines (android), deleting properties make them mutable
-					}catch(e){} 
-					if(originalEvent.type){
-						// deleting properties doesn't work (older iOS), have to use delegation
-						Event.prototype = originalEvent;
-						var event = new Event;
-						// have to delegate methods to make them work
-						event.preventDefault = function(){
-							originalEvent.preventDefault();
-						};
-						event.stopPropagation = function(){
-							originalEvent.stopPropagation();
-						};
-					}else{
-						// deletion worked, use property as is
-						event = originalEvent;
-						event.type = type;
-					}
-					originalEvent.corrected = event;
-					if(type == 'resize'){
-						if(windowOrientation == window.orientation){ 
-							return null;//double tap causes an unexpected 'resize' in Andriod 
-						} 
-						windowOrientation = window.orientation;
-						event.type = "orientationchange"; 
-						return listener.call(this, event);
-					}
-					// We use the original event and augment, rather than doing an expensive mixin operation
-					if(!("rotation" in event)){ // test to see if it has rotation
-						event.rotation = 0; 
-						event.scale = 1;
-					}
-					//use event.changedTouches[0].pageX|pageY|screenX|screenY|clientX|clientY|target
-					var firstChangeTouch = event.changedTouches[0];
-					for(var i in firstChangeTouch){ // use for-in, we don't need to have dependency on dojo/_base/lang here
-						delete event[i]; // delete it first to make it mutable
-						event[i] = firstChangeTouch[i];
-					}
-				}
-				return listener.call(this, event); 
-			}; 
-		}; 
-	}
-	return on;
-});
+define(["./has!dom-addeventlistener?:./aspect", "./_base/kernel", "./has"], function(aspect, dojo, has){
+	// summary:
+	//		The export of this module is a function that provides core event listening functionality. With this function
+	//		you can provide a target, event type, and listener to be notified of
+	//		future matching events that are fired.
+	// target: Element|Object
+	//		This is the target object or DOM element that to receive events from
+	// type: String|Function
+	// 		This is the name of the event to listen for or an extension event type.
+	// listener: Function
+	// 		This is the function that should be called when the event fires.
+	// returns: Object
+	// 		An object with a remove() method that can be used to stop listening for this
+	// 		event.
+	// description:
+	// 		To listen for "click" events on a button node, we can do:
+	// 		|	define(["dojo/on"], function(listen){
+	// 		|		on(button, "click", clickHandler);
+	//		|		...
+	//  	Evented JavaScript objects can also have their own events.
+	// 		|	var obj = new Evented;
+	//		|	on(obj, "foo", fooHandler);
+	//		And then we could publish a "foo" event:
+	//		|	on.emit(obj, "foo", {key: "value"});
+	//		We can use extension events as well. For example, you could listen for a tap gesture:
+	// 		|	define(["dojo/on", "dojo/gesture/tap", function(listen, tap){
+	// 		|		on(button, tap, tapHandler);
+	//		|		...
+	//		which would trigger fooHandler. Note that for a simple object this is equivalent to calling:
+	//		|	obj.onfoo({key:"value"});
+	//		If you use on.emit on a DOM node, it will use native event dispatching when possible.
+
+ 	"use strict";
+	if(has("dom")){ // check to make sure we are in a browser, this module should work anywhere
+		var major = window.ScriptEngineMajorVersion;
+		has.add("jscript", major && (major() + ScriptEngineMinorVersion() / 10));
+		has.add("event-orientationchange", has("touch") && !has("android")); // TODO: how do we detect this?
+	}
+	var on = function(target, type, listener, dontFix){
+		if(target.on){ 
+			// delegate to the target's on() method, so it can handle it's own listening if it wants
+			return target.on(type, listener);
+		}
+		// delegate to main listener code
+		return on.parse(target, type, listener, addListener, dontFix, this);
+	};
+	on.pausable =  function(target, type, listener, dontFix){
+		// summary:
+		//		This function acts the same as on(), but with pausable functionality. The
+		// 		returned signal object has pause() and resume() functions. Calling the
+		//		pause() method will cause the listener to not be called for future events. Calling the
+		//		resume() method will cause the listener to again be called for future events.
+		var paused;
+		var signal = on(target, type, function(){
+			if(!paused){
+				return listener.apply(this, arguments);
+			}
+		}, dontFix);
+		signal.pause = function(){
+			paused = true;
+		};
+		signal.resume = function(){
+			paused = false;
+		};
+		return signal;
+	};
+	on.once = function(target, type, listener, dontFix){
+		// summary:
+		//		This function acts the same as on(), but will only call the listener once. The 
+		// 		listener will be called for the first
+		//		event that takes place and then listener will automatically be removed.
+		var signal = on(target, type, function(){
+			// remove this listener
+			signal.remove();
+			// proceed to call the listener
+			return listener.apply(this, arguments);
+		});
+		return signal;
+	};
+	on.parse = function(target, type, listener, addListener, dontFix, matchesTarget){
+		if(type.call){
+			// event handler function
+			// on(node, dojo.touch.press, touchListener);
+			return type.call(matchesTarget, target, listener);
+		}
+
+		if(type.indexOf(",") > -1){
+			// we allow comma delimited event names, so you can register for multiple events at once
+			var events = type.split(/\s*,\s*/);
+			var handles = [];
+			var i = 0;
+			var eventName;
+			while(eventName = events[i++]){
+				handles.push(addListener(target, eventName, listener, dontFix, matchesTarget));
+			}
+			handles.remove = function(){
+				for(var i = 0; i < handles.length; i++){
+					handles[i].remove();
+				}
+			};
+			return handles;
+		}
+		return addListener(target, type, listener, dontFix, matchesTarget)
+	};
+	var touchEvents = /^touch/;
+	function addListener(target, type, listener, dontFix, matchesTarget){		
+		// event delegation:
+		var selector = type.match(/(.*):(.*)/);
+		// if we have a selector:event, the last one is interpreted as an event, and we use event delegation
+		if(selector){
+			type = selector[2];
+			selector = selector[1];
+			// create the extension event for selectors and directly call it
+			return on.selector(selector, type).call(matchesTarget, target, listener);
+		}
+		// test to see if it a touch event right now, so we don't have to do it every time it fires
+		if(has("touch")){
+			if(touchEvents.test(type)){
+				// touch event, fix it
+				listener = fixTouchListener(listener);
+			}
+			if(!has("event-orientationchange") && (type == "orientationchange")){
+				//"orientationchange" not supported <= Android 2.1, 
+				//but works through "resize" on window
+				type = "resize"; 
+				target = window;
+				listener = fixTouchListener(listener);
+			} 
+		}
+		// normal path, the target is |this|
+		if(target.addEventListener){
+			// the target has addEventListener, which should be used if available (might or might not be a node, non-nodes can implement this method as well)
+			// check for capture conversions
+			var capture = type in captures;
+			target.addEventListener(capture ? captures[type] : type, listener, capture);
+			// create and return the signal
+			return {
+				remove: function(){
+					target.removeEventListener(type, listener, capture);
+				}
+			};
+		}
+		type = "on" + type;
+		if(fixAttach && target.attachEvent){
+			return fixAttach(target, type, listener);
+		}
+	 	throw new Error("Target must be an event emitter");
+	}
+
+	on.selector = function(selector, eventType, children){
+		// summary:
+		//		Creates a new extension event with event delegation. This is based on
+		// 		the provided event type (can be extension event) that
+		// 		only calls the listener when the CSS selector matches the target of the event.
+		//	selector:
+		//		The CSS selector to use for filter events and determine the |this| of the event listener.
+		//	eventType:
+		//		The event to listen for
+		// children:
+		//		Indicates if children elements of the selector should be allowed. This defaults to 
+		// 		true (except in the case of normally non-bubbling events like mouse.enter, in which case it defaults to false).
+		//	example:
+		//		define(["dojo/on", "dojo/mouse"], function(listen, mouse){
+		//			on(node, on.selector(".my-class", mouse.enter), handlerForMyHover);
+		return function(target, listener){
+			var matchesTarget = this;
+			var bubble = eventType.bubble;
+			if(bubble){
+				// the event type doesn't naturally bubble, but has a bubbling form, use that
+				eventType = bubble;
+			}else if(children !== false){
+				// for normal bubbling events we default to allowing children of the selector
+				children = true;
+			}
+			return on(target, eventType, function(event){
+				var eventTarget = event.target;
+				// see if we have a valid matchesTarget or default to dojo.query
+				matchesTarget = matchesTarget && matchesTarget.matches ? matchesTarget : dojo.query;
+				// there is a selector, so make sure it matches
+				while(!matchesTarget.matches(eventTarget, selector, target)){
+					if(eventTarget == target || !children || !(eventTarget = eventTarget.parentNode)){ // intentional assignment
+						return;
+					}
+				}
+				return listener.call(eventTarget, event);
+			});
+		};
+	};
+
+	function syntheticPreventDefault(){
+		this.cancelable = false;
+	}
+	function syntheticStopPropagation(){
+		this.bubbles = false;
+	}
+	var slice = [].slice,
+		syntheticDispatch = on.emit = function(target, type, event){
+		// summary:
+		//		Fires an event on the target object.
+		//	target:
+		//		The target object to fire the event on. This can be a DOM element or a plain 
+		// 		JS object. If the target is a DOM element, native event emiting mechanisms
+		//		are used when possible.
+		//	type:
+		//		The event type name. You can emulate standard native events like "click" and 
+		// 		"mouseover" or create custom events like "open" or "finish".
+		//	event:
+		//		An object that provides the properties for the event. See https://developer.mozilla.org/en/DOM/event.initEvent 
+		// 		for some of the properties. These properties are copied to the event object.
+		//		Of particular importance are the cancelable and bubbles properties. The
+		//		cancelable property indicates whether or not the event has a default action
+		// 		that can be cancelled. The event is cancelled by calling preventDefault() on
+		// 		the event object. The bubbles property indicates whether or not the
+		//		event will bubble up the DOM tree. If bubbles is true, the event will be called
+		//		on the target and then each parent successively until the top of the tree
+		//		is reached or stopPropagation() is called. Both bubbles and cancelable 
+		// 		default to false.
+		//	returns:
+		//		If the event is cancelable and the event is not cancelled,
+		// 		emit will return true. If the event is cancelable and the event is cancelled,
+		// 		emit will return false.
+		//	details:
+		//		Note that this is designed to emit events for listeners registered through
+		//		dojo/on. It should actually work with any event listener except those
+		// 		added through IE's attachEvent (IE8 and below's non-W3C event emiting
+		// 		doesn't support custom event types). It should work with all events registered
+		// 		through dojo/on. Also note that the emit method does do any default
+		// 		action, it only returns a value to indicate if the default action should take
+		// 		place. For example, emiting a keypress event would not cause a character
+		// 		to appear in a textbox.
+		//	example:
+		//		To fire our own click event
+		//	|	on.emit(dojo.byId("button"), "click", {
+		//	|		cancelable: true,
+		//	|		bubbles: true,
+		//	|		screenX: 33,
+		//	|		screenY: 44
+		//	|	});
+		//		We can also fire our own custom events:
+		//	|	on.emit(dojo.byId("slider"), "slide", {
+		//	|		cancelable: true,
+		//	|		bubbles: true,
+		//	|		direction: "left-to-right"
+		//	|	});
+		var args = slice.call(arguments, 2);
+		var method = "on" + type;
+		if("parentNode" in target){
+			// node (or node-like), create event controller methods
+			var newEvent = args[0] = {};
+			for(var i in event){
+				newEvent[i] = event[i];
+			}
+			newEvent.preventDefault = syntheticPreventDefault;
+			newEvent.stopPropagation = syntheticStopPropagation;
+			newEvent.target = target;
+			newEvent.type = type;
+			event = newEvent;
+		}
+		do{
+			// call any node which has a handler (note that ideally we would try/catch to simulate normal event propagation but that causes too much pain for debugging)
+			target[method] && target[method].apply(target, args);
+			// and then continue up the parent node chain if it is still bubbling (if started as bubbles and stopPropagation hasn't been called)
+		}while(event && event.bubbles && (target = target.parentNode));
+		return event && event.cancelable && event; // if it is still true (was cancelable and was cancelled), return the event to indicate default action should happen
+	};
+	var captures = {}; 
+	if(has("dom-addeventlistener")){
+		// normalize focusin and focusout
+		captures = {
+			focusin: "focus",
+			focusout: "blur"
+		};
+		if(has("opera")){
+			captures.keydown = "keypress"; // this one needs to be transformed because Opera doesn't support repeating keys on keydown (and keypress works because it incorrectly fires on all keydown events)
+		}
+
+		// emiter that works with native event handling
+		on.emit = function(target, type, event){
+			if(target.dispatchEvent && document.createEvent){
+				// use the native event emiting mechanism if it is available on the target object
+				// create a generic event				
+				// we could create branch into the different types of event constructors, but 
+				// that would be a lot of extra code, with little benefit that I can see, seems 
+				// best to use the generic constructor and copy properties over, making it 
+				// easy to have events look like the ones created with specific initializers
+				var nativeEvent = document.createEvent("HTMLEvents");
+				nativeEvent.initEvent(type, !!event.bubbles, !!event.cancelable);
+				// and copy all our properties over
+				for(var i in event){
+					var value = event[i];
+					if(!(i in nativeEvent)){
+						nativeEvent[i] = event[i];
+					}
+				}
+				return target.dispatchEvent(nativeEvent) && nativeEvent;
+			}
+			return syntheticDispatch.apply(on, arguments); // emit for a non-node
+		};
+	}else{
+		// no addEventListener, basically old IE event normalization
+		on._fixEvent = function(evt, sender){
+			// summary:
+			//		normalizes properties on the event object including event
+			//		bubbling methods, keystroke normalization, and x/y positions
+			// evt:
+			//		native event object
+			// sender:
+			//		node to treat as "currentTarget"
+			if(!evt){
+				var w = sender && (sender.ownerDocument || sender.document || sender).parentWindow || window;
+				evt = w.event;
+			}
+			if(!evt){return(evt);}
+			if(!evt.target){ // check to see if it has been fixed yet
+				evt.target = evt.srcElement;
+				evt.currentTarget = (sender || evt.srcElement);
+				if(evt.type == "mouseover"){
+					evt.relatedTarget = evt.fromElement;
+				}
+				if(evt.type == "mouseout"){
+					evt.relatedTarget = evt.toElement;
+				}
+				if(!evt.stopPropagation){
+					evt.stopPropagation = stopPropagation;
+					evt.preventDefault = preventDefault;
+				}
+				switch(evt.type){
+					case "keypress":
+						var c = ("charCode" in evt ? evt.charCode : evt.keyCode);
+						if (c==10){
+							// CTRL-ENTER is CTRL-ASCII(10) on IE, but CTRL-ENTER on Mozilla
+							c=0;
+							evt.keyCode = 13;
+						}else if(c==13||c==27){
+							c=0; // Mozilla considers ENTER and ESC non-printable
+						}else if(c==3){
+							c=99; // Mozilla maps CTRL-BREAK to CTRL-c
+						}
+						// Mozilla sets keyCode to 0 when there is a charCode
+						// but that stops the event on IE.
+						evt.charCode = c;
+						_setKeyChar(evt);
+						break;
+				}
+			}
+			return evt;
+		};
+		var IESignal = function(handle){
+			this.handle = handle;
+		};
+		IESignal.prototype.remove = function(){
+			delete _dojoIEListeners_[this.handle];
+		};
+		var fixListener = function(listener){
+			// this is a minimal function for closing on the previous listener with as few as variables as possible
+			return function(evt){
+				evt = on._fixEvent(evt, this);
+				return listener.call(this, evt);
+			}
+		}
+		var fixAttach = function(target, type, listener){
+			listener = fixListener(listener);
+			if(((target.ownerDocument ? target.ownerDocument.parentWindow : target.parentWindow || target.window || window) != top || 
+						has("jscript") < 5.8) && 
+					!has("config-_allow_leaks")){
+				// IE will leak memory on certain handlers in frames (IE8 and earlier) and in unattached DOM nodes for JScript 5.7 and below.
+				// Here we use global redirection to solve the memory leaks
+				if(typeof _dojoIEListeners_ == "undefined"){
+					_dojoIEListeners_ = [];
+				}
+				var emiter = target[type];
+				if(!emiter || !emiter.listeners){
+					var oldListener = emiter;
+					target[type] = emiter = Function('event', 'var callee = arguments.callee; for(var i = 0; i<callee.listeners.length; i++){var listener = _dojoIEListeners_[callee.listeners[i]]; if(listener){listener.call(this,event);}}');
+					emiter.listeners = [];
+					if(oldListener){
+						emiter.listeners.push(_dojoIEListeners_.push(oldListener) - 1);
+					}
+				}
+				var handle;
+				emiter.listeners.push(handle = (_dojoIEListeners_.push(listener) - 1));
+				return new IESignal(handle);
+			}
+			return aspect.after(target, type, listener, true);
+		};
+
+		var _setKeyChar = function(evt){
+			evt.keyChar = evt.charCode ? String.fromCharCode(evt.charCode) : '';
+			evt.charOrCode = evt.keyChar || evt.keyCode;
+		};
+		// Called in Event scope
+		var stopPropagation = function(){
+			this.cancelBubble = true;
+		};
+		var preventDefault = on._preventDefault = function(){
+			// Setting keyCode to 0 is the only way to prevent certain keypresses (namely
+			// ctrl-combinations that correspond to menu accelerator keys).
+			// Otoh, it prevents upstream listeners from getting this information
+			// Try to split the difference here by clobbering keyCode only for ctrl
+			// combinations. If you still need to access the key upstream, bubbledKeyCode is
+			// provided as a workaround.
+			this.bubbledKeyCode = this.keyCode;
+			if(this.ctrlKey){
+				try{
+					// squelch errors when keyCode is read-only
+					// (e.g. if keyCode is ctrl or shift)
+					this.keyCode = 0;
+				}catch(e){
+				}
+			}
+			this.returnValue = false;
+		};
+	}
+	if(has("touch")){ 
+		var Event = function (){};
+		var windowOrientation = window.orientation; 
+		var fixTouchListener = function(listener){ 
+			return function(originalEvent){ 
+				//Event normalization(for ontouchxxx and resize): 
+				//1.incorrect e.pageX|pageY in iOS 
+				//2.there are no "e.rotation", "e.scale" and "onorientationchange" in Andriod
+				//3.More TBD e.g. force | screenX | screenX | clientX | clientY | radiusX | radiusY
+
+				// see if it has already been corrected
+				var event = originalEvent.corrected;
+				if(!event){
+					var type = originalEvent.type;
+					try{
+						delete originalEvent.type; // on some JS engines (android), deleting properties make them mutable
+					}catch(e){} 
+					if(originalEvent.type){
+						// deleting properties doesn't work (older iOS), have to use delegation
+						Event.prototype = originalEvent;
+						var event = new Event;
+						// have to delegate methods to make them work
+						event.preventDefault = function(){
+							originalEvent.preventDefault();
+						};
+						event.stopPropagation = function(){
+							originalEvent.stopPropagation();
+						};
+					}else{
+						// deletion worked, use property as is
+						event = originalEvent;
+						event.type = type;
+					}
+					originalEvent.corrected = event;
+					if(type == 'resize'){
+						if(windowOrientation == window.orientation){ 
+							return null;//double tap causes an unexpected 'resize' in Andriod 
+						} 
+						windowOrientation = window.orientation;
+						event.type = "orientationchange"; 
+						return listener.call(this, event);
+					}
+					// We use the original event and augment, rather than doing an expensive mixin operation
+					if(!("rotation" in event)){ // test to see if it has rotation
+						event.rotation = 0; 
+						event.scale = 1;
+					}
+					//use event.changedTouches[0].pageX|pageY|screenX|screenY|clientX|clientY|target
+					var firstChangeTouch = event.changedTouches[0];
+					for(var i in firstChangeTouch){ // use for-in, we don't need to have dependency on dojo/_base/lang here
+						delete event[i]; // delete it first to make it mutable
+						event[i] = firstChangeTouch[i];
+					}
+				}
+				return listener.call(this, event); 
+			}; 
+		}; 
+	}
+	return on;
+});
diff --git a/query.js b/query.js
index 9aa601c..2f1aeab 100644
--- a/query.js
+++ b/query.js
@@ -1,712 +1,712 @@
-define(["./_base/kernel", "./has", "./on", "./_base/array", "./_base/lang", "./selector/_loader", "./selector/_loader!default"], function(dojo, has, on, array, lang, loader, defaultEngine){
-"use strict";
-
-	has.add("array-extensible", function(){
-		// test to see if we can extend an array (not supported in old IE)
-		return lang.delegate([], {length: 1}).length == 1 && !has("bug-for-in-skips-shadowed");
-	});
-	
-	var ap = Array.prototype, aps = ap.slice, apc = ap.concat, forEach = array.forEach;
-
-	var tnl = function(/*Array*/ a, /*dojo.NodeList?*/ parent, /*Function?*/ NodeListCtor){
-		// summary:
-		//		decorate an array to make it look like a `dojo.NodeList`.
-		// a:
-		//		Array of nodes to decorate.
-		// parent:
-		//		An optional parent NodeList that generated the current
-		//		list of nodes. Used to call _stash() so the parent NodeList
-		//		can be accessed via end() later.
-		// NodeListCtor:
-		//		An optional constructor function to use for any
-		//		new NodeList calls. This allows a certain chain of
-		//		NodeList calls to use a different object than dojo.NodeList.
-		var nodeList = new (NodeListCtor || this._NodeListCtor || nl)(a);
-		return parent ? nodeList._stash(parent) : nodeList;
-	};
-
-	var loopBody = function(f, a, o){
-		a = [0].concat(aps.call(a, 0));
-		o = o || dojo.global;
-		return function(node){
-			a[0] = node;
-			return f.apply(o, a);
-		};
-	};
-
-	// adapters
-
-	var adaptAsForEach = function(f, o){
-		// summary:
-		//		adapts a single node function to be used in the forEach-type
-		//		actions. The initial object is returned from the specialized
-		//		function.
-		// f: Function
-		//		a function to adapt
-		// o: Object?
-		//		an optional context for f
-		return function(){
-			this.forEach(loopBody(f, arguments, o));
-			return this;	// Object
-		};
-	};
-
-	var adaptAsMap = function(f, o){
-		// summary:
-		//		adapts a single node function to be used in the map-type
-		//		actions. The return is a new array of values, as via `dojo.map`
-		// f: Function
-		//		a function to adapt
-		// o: Object?
-		//		an optional context for f
-		return function(){
-			return this.map(loopBody(f, arguments, o));
-		};
-	};
-
-	var adaptAsFilter = function(f, o){
-		// summary:
-		//		adapts a single node function to be used in the filter-type actions
-		// f: Function
-		//		a function to adapt
-		// o: Object?
-		//		an optional context for f
-		return function(){
-			return this.filter(loopBody(f, arguments, o));
-		};
-	};
-
-	var adaptWithCondition = function(f, g, o){
-		// summary:
-		//		adapts a single node function to be used in the map-type
-		//		actions, behaves like forEach() or map() depending on arguments
-		// f: Function
-		//		a function to adapt
-		// g: Function
-		//		a condition function, if true runs as map(), otherwise runs as forEach()
-		// o: Object?
-		//		an optional context for f and g
-		return function(){
-			var a = arguments, body = loopBody(f, a, o);
-			if(g.call(o || dojo.global, a)){
-				return this.map(body);	// self
-			}
-			this.forEach(body);
-			return this;	// self
-		};
-	};
-
-	var NodeList = function(array){
-		// summary:
-		//		dojo.NodeList is an of Array-like object which adds syntactic
-		//		sugar for chaining, common iteration operations, animation, and
-		//		node manipulation. NodeLists are most often returned as the
-		//		result of dojo.query() calls.
-		// description:
-		//		dojo.NodeList instances provide many utilities that reflect
-		//		core Dojo APIs for Array iteration and manipulation, DOM
-		//		manipulation, and event handling. Instead of needing to dig up
-		//		functions in the dojo.* namespace, NodeLists generally make the
-		//		full power of Dojo available for DOM manipulation tasks in a
-		//		simple, chainable way.
-		// example:
-		//		create a node list from a node
-		//		|	new dojo.NodeList(dojo.byId("foo"));
-		// example:
-		//		get a NodeList from a CSS query and iterate on it
-		//		|	var l = dojo.query(".thinger");
-		//		|	l.forEach(function(node, index, nodeList){
-		//		|		console.log(index, node.innerHTML);
-		//		|	});
-		// example:
-		//		use native and Dojo-provided array methods to manipulate a
-		//		NodeList without needing to use dojo.* functions explicitly:
-		//		|	var l = dojo.query(".thinger");
-		//		|	// since NodeLists are real arrays, they have a length
-		//		|	// property that is both readable and writable and
-		//		|	// push/pop/shift/unshift methods
-		//		|	console.log(l.length);
-		//		|	l.push(dojo.create("span"));
-		//		|
-		//		|	// dojo's normalized array methods work too:
-		//		|	console.log( l.indexOf(dojo.byId("foo")) );
-		//		|	// ...including the special "function as string" shorthand
-		//		|	console.log( l.every("item.nodeType == 1") );
-		//		|
-		//		|	// NodeLists can be [..] indexed, or you can use the at()
-		//		|	// function to get specific items wrapped in a new NodeList:
-		//		|	var node = l[3]; // the 4th element
-		//		|	var newList = l.at(1, 3); // the 2nd and 4th elements
-		// example:
-		//		the style functions you expect are all there too:
-		//		|	// style() as a getter...
-		//		|	var borders = dojo.query(".thinger").style("border");
-		//		|	// ...and as a setter:
-		//		|	dojo.query(".thinger").style("border", "1px solid black");
-		//		|	// class manipulation
-		//		|	dojo.query("li:nth-child(even)").addClass("even");
-		//		|	// even getting the coordinates of all the items
-		//		|	var coords = dojo.query(".thinger").coords();
-		// example:
-		//		DOM manipulation functions from the dojo.* namespace area also
-		//		available:
-		//		|	// remove all of the elements in the list from their
-		//		|	// parents (akin to "deleting" them from the document)
-		//		|	dojo.query(".thinger").orphan();
-		//		|	// place all elements in the list at the front of #foo
-		//		|	dojo.query(".thinger").place("foo", "first");
-		// example:
-		//		Event handling couldn't be easier. `dojo.connect` is mapped in,
-		//		and shortcut handlers are provided for most DOM events:
-		//		|	// like dojo.connect(), but with implicit scope
-		//		|	dojo.query("li").connect("onclick", console, "log");
-		//		|
-		//		|	// many common event handlers are already available directly:
-		//		|	dojo.query("li").onclick(console, "log");
-		//		|	var toggleHovered = dojo.hitch(dojo, "toggleClass", "hovered");
-		//		|	dojo.query("p")
-		//		|		.onmouseenter(toggleHovered)
-		//		|		.onmouseleave(toggleHovered);
-		// example:
-		//		chainability is a key advantage of NodeLists:
-		//		|	dojo.query(".thinger")
-		//		|		.onclick(function(e){ /* ... */ })
-		//		|		.at(1, 3, 8) // get a subset
-		//		|			.style("padding", "5px")
-		//		|			.forEach(console.log);
-		var isNew = this instanceof nl && has("array-extensible");
-		if(typeof array == "number"){
-			array = Array(array);
-		}
-		var nodeArray = (array && "length" in array) ? array : arguments;
-		if(isNew || !nodeArray.sort){
-			// make sure it's a real array before we pass it on to be wrapped 
-			var target = isNew ? this : [],
-				l = target.length = nodeArray.length;
-			for(var i = 0; i < l; i++){
-				target[i] = nodeArray[i];
-			}
-			if(isNew){
-				// called with new operator, this means we are going to use this instance and push
-				// the nodes on to it. This is usually much faster since the NodeList properties
-				//	don't need to be copied (unless the list of nodes is extremely large).
-				return target;
-			}
-			nodeArray = target;
-		}
-		// called without new operator, use a real array and copy prototype properties,
-		// this is slower and exists for back-compat. Should be removed in 2.0.
-		lang._mixin(nodeArray, nlp);
-		nodeArray._NodeListCtor = function(array){
-			// call without new operator to preserve back-compat behavior
-			return nl(array);
-		}
-		return nodeArray;
-	};
-	
-	var nl = NodeList, nlp = nl.prototype = 
-		has("array-extensible") ? [] : {};// extend an array if it is extensible
-
-	// expose adapters and the wrapper as private functions
-
-	nl._wrap = nlp._wrap = tnl;
-	nl._adaptAsMap = adaptAsMap;
-	nl._adaptAsForEach = adaptAsForEach;
-	nl._adaptAsFilter  = adaptAsFilter;
-	nl._adaptWithCondition = adaptWithCondition;
-
-	// mass assignment
-
-	// add array redirectors
-	forEach(["slice", "splice"], function(name){
-		var f = ap[name];
-		//Use a copy of the this array via this.slice() to allow .end() to work right in the splice case.
-		// CANNOT apply ._stash()/end() to splice since it currently modifies
-		// the existing this array -- it would break backward compatibility if we copy the array before
-		// the splice so that we can use .end(). So only doing the stash option to this._wrap for slice.
-		nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); };
-	});
-	// concat should be here but some browsers with native NodeList have problems with it
-
-	// add array.js redirectors
-	forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){
-		var f = array[name];
-		nlp[name] = function(){ return f.apply(dojo, [this].concat(aps.call(arguments, 0))); };
-	});
-
-	/*===== var NodeList = dojo.NodeList; =====*/
-	lang.extend(NodeList, {
-		// copy the constructors
-		constructor: nl,
-		_NodeListCtor: nl,
-		toString: function(){
-			// Array.prototype.toString can't be applied to objects, so we use join
-			return this.join(",");
-		},
-		_stash: function(parent){
-			// summary:
-			//		private function to hold to a parent NodeList. end() to return the parent NodeList.
-			//
-			// example:
-			// How to make a `dojo.NodeList` method that only returns the third node in
-			// the dojo.NodeList but allows access to the original NodeList by using this._stash:
-			//	|	dojo.extend(dojo.NodeList, {
-			//	|		third: function(){
-			//	|			var newNodeList = dojo.NodeList(this[2]);
-			//	|			return newNodeList._stash(this);
-			//	|		}
-			//	|	});
-			//	|	// then see how _stash applies a sub-list, to be .end()'ed out of
-			//	|	dojo.query(".foo")
-			//	|		.third()
-			//	|			.addClass("thirdFoo")
-			//	|		.end()
-			//	|		// access to the orig .foo list
-			//	|		.removeClass("foo")
-			//	|
-			//
-			this._parent = parent;
-			return this; //dojo.NodeList
-		},
-
-		on: function(eventName, listener){
-			// summary:
-			//		Listen for events on the nodes in the NodeList. Basic usage is:
-			//		| query(".my-class").on("click", listener);
-			// 		This supports event delegation by using selectors as the first argument with the event names as
-			//		pseudo selectors. For example:
-			//		| dojo.query("#my-list").on("li:click", listener);
-			//		This will listen for click events within <li> elements that are inside the #my-list element.
-			//		Because on supports CSS selector syntax, we can use comma-delimited events as well:
-			//		| dojo.query("#my-list").on("li button:mouseover, li:click", listener);
-			var handles = this.map(function(node){
-				return on(node, eventName, listener); // TODO: apply to the NodeList so the same selector engine is used for matches
-			});
-			handles.remove = function(){
-				for(var i = 0; i < handles.length; i++){
-					handles[i].remove();
-				}
-			};
-			return handles;
-		},
-
-		end: function(){
-			// summary:
-			//		Ends use of the current `dojo.NodeList` by returning the previous dojo.NodeList
-			//		that generated the current dojo.NodeList.
-			// description:
-			//		Returns the `dojo.NodeList` that generated the current `dojo.NodeList`. If there
-			//		is no parent dojo.NodeList, an empty dojo.NodeList is returned.
-			// example:
-			//	|	dojo.query("a")
-			//	|		.filter(".disabled")
-			//	|			// operate on the anchors that only have a disabled class
-			//	|			.style("color", "grey")
-			//	|		.end()
-			//	|		// jump back to the list of anchors
-			//	|		.style(...)
-			//
-			if(this._parent){
-				return this._parent;
-			}else{
-				//Just return empty list.
-				return new this._NodeListCtor(0);
-			}
-		},
-
-		// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
-
-		// FIXME: handle return values for #3244
-		//		http://trac.dojotoolkit.org/ticket/3244
-
-		// FIXME:
-		//		need to wrap or implement:
-		//			join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
-		//			reduce
-		//			reduceRight
-
-		/*=====
-		slice: function(begin, end){
-			// summary:
-			//		Returns a new NodeList, maintaining this one in place
-			// description:
-			//		This method behaves exactly like the Array.slice method
-			//		with the caveat that it returns a dojo.NodeList and not a
-			//		raw Array. For more details, see Mozilla's (slice
-			//		documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice]
-			// begin: Integer
-			//		Can be a positive or negative integer, with positive
-			//		integers noting the offset to begin at, and negative
-			//		integers denoting an offset from the end (i.e., to the left
-			//		of the end)
-			// end: Integer?
-			//		Optional parameter to describe what position relative to
-			//		the NodeList's zero index to end the slice at. Like begin,
-			//		can be positive or negative.
-			return this._wrap(a.slice.apply(this, arguments));
-		},
-
-		splice: function(index, howmany, item){
-			// summary:
-			//		Returns a new NodeList, manipulating this NodeList based on
-			//		the arguments passed, potentially splicing in new elements
-			//		at an offset, optionally deleting elements
-			// description:
-			//		This method behaves exactly like the Array.splice method
-			//		with the caveat that it returns a dojo.NodeList and not a
-			//		raw Array. For more details, see Mozilla's (splice
-			//		documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice]
-			//		For backwards compatibility, calling .end() on the spliced NodeList
-			//		does not return the original NodeList -- splice alters the NodeList in place.
-			// index: Integer
-			//		begin can be a positive or negative integer, with positive
-			//		integers noting the offset to begin at, and negative
-			//		integers denoting an offset from the end (i.e., to the left
-			//		of the end)
-			// howmany: Integer?
-			//		Optional parameter to describe what position relative to
-			//		the NodeList's zero index to end the slice at. Like begin,
-			//		can be positive or negative.
-			// item: Object...?
-			//		Any number of optional parameters may be passed in to be
-			//		spliced into the NodeList
-			// returns:
-			//		dojo.NodeList
-			return this._wrap(a.splice.apply(this, arguments));
-		},
-
-		indexOf: function(value, fromIndex){
-			// summary:
-			//		see dojo.indexOf(). The primary difference is that the acted-on
-			//		array is implicitly this NodeList
-			// value: Object:
-			//		The value to search for.
-			// fromIndex: Integer?:
-			//		The location to start searching from. Optional. Defaults to 0.
-			// description:
-			//		For more details on the behavior of indexOf, see Mozilla's
-			//		(indexOf
-			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf]
-			// returns:
-			//		Positive Integer or 0 for a match, -1 of not found.
-			return d.indexOf(this, value, fromIndex); // Integer
-		},
-
-		lastIndexOf: function(value, fromIndex){
-			// summary:
-			//		see dojo.lastIndexOf(). The primary difference is that the
-			//		acted-on array is implicitly this NodeList
-			// description:
-			//		For more details on the behavior of lastIndexOf, see
-			//		Mozilla's (lastIndexOf
-			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf]
-			// value: Object
-			//		The value to search for.
-			// fromIndex: Integer?
-			//		The location to start searching from. Optional. Defaults to 0.
-			// returns:
-			//		Positive Integer or 0 for a match, -1 of not found.
-			return d.lastIndexOf(this, value, fromIndex); // Integer
-		},
-
-		every: function(callback, thisObject){
-			// summary:
-			//		see `dojo.every()` and the (Array.every
-			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every].
-			//		Takes the same structure of arguments and returns as
-			//		dojo.every() with the caveat that the passed array is
-			//		implicitly this NodeList
-			// callback: Function: the callback
-			// thisObject: Object?: the context
-			return d.every(this, callback, thisObject); // Boolean
-		},
-
-		some: function(callback, thisObject){
-			// summary:
-			//		Takes the same structure of arguments and returns as
-			//		`dojo.some()` with the caveat that the passed array is
-			//		implicitly this NodeList.  See `dojo.some()` and Mozilla's
-			//		(Array.some
-			//		documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some].
-			// callback: Function: the callback
-			// thisObject: Object?: the context
-			return d.some(this, callback, thisObject); // Boolean
-		},
-		=====*/
-
-		concat: function(item){
-			// summary:
-			//		Returns a new NodeList comprised of items in this NodeList
-			//		as well as items passed in as parameters
-			// description:
-			//		This method behaves exactly like the Array.concat method
-			//		with the caveat that it returns a `dojo.NodeList` and not a
-			//		raw Array. For more details, see the (Array.concat
-			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat]
-			// item: Object?
-			//		Any number of optional parameters may be passed in to be
-			//		spliced into the NodeList
-			// returns:
-			//		dojo.NodeList
-
-			//return this._wrap(apc.apply(this, arguments));
-			// the line above won't work for the native NodeList :-(
-
-			// implementation notes:
-			// 1) Native NodeList is not an array, and cannot be used directly
-			// in concat() --- the latter doesn't recognize it as an array, and
-			// does not inline it, but append as a single entity.
-			// 2) On some browsers (e.g., Safari) the "constructor" property is
-			// read-only and cannot be changed. So we have to test for both
-			// native NodeList and dojo.NodeList in this property to recognize
-			// the node list.
-
-			var t = lang.isArray(this) ? this : aps.call(this, 0),
-				m = array.map(arguments, function(a){
-					return a && !lang.isArray(a) &&
-						(typeof NodeList != "undefined" && a.constructor === NodeList || a.constructor === this._NodeListCtor) ?
-							aps.call(a, 0) : a;
-				});
-			return this._wrap(apc.apply(t, m), this);	// dojo.NodeList
-		},
-
-		map: function(/*Function*/ func, /*Function?*/ obj){
-			// summary:
-			//		see dojo.map(). The primary difference is that the acted-on
-			//		array is implicitly this NodeList and the return is a
-			//		dojo.NodeList (a subclass of Array)
-			///return d.map(this, func, obj, d.NodeList); // dojo.NodeList
-			return this._wrap(array.map(this, func, obj), this); // dojo.NodeList
-		},
-
-		forEach: function(callback, thisObj){
-			// summary:
-			//		see `dojo.forEach()`. The primary difference is that the acted-on
-			//		array is implicitly this NodeList. If you want the option to break out
-			//		of the forEach loop, use every() or some() instead.
-			forEach(this, callback, thisObj);
-			// non-standard return to allow easier chaining
-			return this; // dojo.NodeList
-		},
-		filter: function(/*String|Function*/ filter){
-			// summary:
-			//		"masks" the built-in javascript filter() method (supported
-			//		in Dojo via `dojo.filter`) to support passing a simple
-			//		string filter in addition to supporting filtering function
-			//		objects.
-			// filter:
-			//		If a string, a CSS rule like ".thinger" or "div > span".
-			// example:
-			//		"regular" JS filter syntax as exposed in dojo.filter:
-			//		|	dojo.query("*").filter(function(item){
-			//		|		// highlight every paragraph
-			//		|		return (item.nodeName == "p");
-			//		|	}).style("backgroundColor", "yellow");
-			// example:
-			//		the same filtering using a CSS selector
-			//		|	dojo.query("*").filter("p").styles("backgroundColor", "yellow");
-
-			var a = arguments, items = this, start = 0;
-			if(typeof filter == "string"){ // inline'd type check
-				items = query._filterResult(this, a[0]);
-				if(a.length == 1){
-					// if we only got a string query, pass back the filtered results
-					return items._stash(this); // dojo.NodeList
-				}
-				// if we got a callback, run it over the filtered items
-				start = 1;
-			}
-			return this._wrap(array.filter(items, a[start], a[start + 1]), this);	// dojo.NodeList
-		},
-		instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
-			// summary:
-			//		Create a new instance of a specified class, using the
-			//		specified properties and each node in the nodeList as a
-			//		srcNodeRef.
-			// example:
-			//		Grabs all buttons in the page and converts them to diji.form.Buttons.
-			//	|	var buttons = dojo.query("button").instantiate("dijit.form.Button", {showLabel: true});
-			var c = lang.isFunction(declaredClass) ? declaredClass : lang.getObject(declaredClass);
-			properties = properties || {};
-			return this.forEach(function(node){
-				new c(properties, node);
-			});	// dojo.NodeList
-		},
-		at: function(/*===== index =====*/){
-			// summary:
-			//		Returns a new NodeList comprised of items in this NodeList
-			//		at the given index or indices.
-			//
-			// index: Integer...
-			//		One or more 0-based indices of items in the current
-			//		NodeList. A negative index will start at the end of the
-			//		list and go backwards.
-			//
-			// example:
-			//	Shorten the list to the first, second, and third elements
-			//	|	dojo.query("a").at(0, 1, 2).forEach(fn);
-			//
-			// example:
-			//	Retrieve the first and last elements of a unordered list:
-			//	|	dojo.query("ul > li").at(0, -1).forEach(cb);
-			//
-			// example:
-			//	Do something for the first element only, but end() out back to
-			//	the original list and continue chaining:
-			//	|	dojo.query("a").at(0).onclick(fn).end().forEach(function(n){
-			//	|		console.log(n); // all anchors on the page.
-			//	|	})
-			//
-			// returns:
-			//		dojo.NodeList
-			var t = new this._NodeListCtor(0);
-			forEach(arguments, function(i){
-				if(i < 0){ i = this.length + i; }
-				if(this[i]){ t.push(this[i]); }
-			}, this);
-			return t._stash(this); // dojo.NodeList
-		}
-	});
-
-
-/*===== 
-dojo.query = function(selector, context){
-	// summary:
-	//		This modules provides DOM querying functionality. The module export is a function
-	//		that can be used to query for DOM nodes by CSS selector and returns a dojo.NodeList
-	//		representing the matching nodes.
-	//
-	// selector: String
-	//		A CSS selector to search for.
-	// context: String|DomNode?
-	//		An optional context to limit the searching scope. Only nodes under `context` will be 
-	//		scanned. 
-	// 
-	//	example:
-	//		add an onclick handler to every submit button in the document
-	//		which causes the form to be sent via Ajax instead:
-	//	|	define(["dojo/query"], function(query){
-	// 	|	query("input[type='submit']").on("click", function(e){
-	//	|		dojo.stopEvent(e); // prevent sending the form
-	//	|		var btn = e.target;
-	//	|		dojo.xhrPost({
-	//	|			form: btn.form,
-	//	|			load: function(data){
-	//	|				// replace the form with the response
-	//	|				var div = dojo.doc.createElement("div");
-	//	|				dojo.place(div, btn.form, "after");
-	//	|				div.innerHTML = data;
-	//	|				dojo.style(btn.form, "display", "none");
-	//	|			}
-	//	|		});
-	//	|	}); 
-	//
-	// description:
-	//		dojo/query is responsible for loading the appropriate query engine and wrapping 
-	//		its results with a `dojo.NodeList`. You can use dojo/query with a specific selector engine
-	//		by using it as a plugin. For example, if you installed the sizzle package, you could
-	//		use it as the selector engine with:
-	//		|	define("dojo/query!sizzle", function(query){
-	//		|		query("div")...
-	//
-	//		The id after the ! can be a module id of the selector engine or one of the following values:
-	//		|	+ acme: This is the default engine used by Dojo base, and will ensure that the full
-	//		|	Acme engine is always loaded. 
-	//		|	
-	//		|	+ css2: If the browser has a native selector engine, this will be used, otherwise a
-	//		|	very minimal lightweight selector engine will be loaded that can do simple CSS2 selectors
-	//		|	(by #id, .class, tag, and [name=value] attributes, with standard child or descendant (>)
-	//		|	operators) and nothing more.
-	//		|
-	//		|	+ css2.1: If the browser has a native selector engine, this will be used, otherwise the
-	//		|	full Acme engine will be loaded. 
-	//		|	
-	//		|	+ css3: If the browser has a native selector engine with support for CSS3 pseudo
-	//		|	selectors (most modern browsers except IE8), this will be used, otherwise the
-	//		|	full Acme engine will be loaded.
-	//		|	
-	//		|	+ Or the module id of a selector engine can be used to explicitly choose the selector engine
-	//		
-	//		For example, if you are using CSS3 pseudo selectors in module, you can specify that
-	//		you will need support them with:
-	//		|	define("dojo/query!css3", function(query){
-	//		|		query('#t > h3:nth-child(odd)')...
-	//
-	//		You can also choose the selector engine/load configuration by setting the <FIXME:what is the configuration setting?>.
-	//		For example:
-	//		|	<script data-dojo-config="query-selector:'css3'" src="dojo.js"></script>
-	//		
-	return new dojo.NodeList(); // dojo.NodeList
-};
-=====*/
-
-function queryForEngine(engine, NodeList){
-	var query = function(/*String*/ query, /*String|DOMNode?*/ root){
-		//	summary:
-		//		Returns nodes which match the given CSS selector, searching the
-		//		entire document by default but optionally taking a node to scope
-		//		the search by. Returns an instance of dojo.NodeList.
-		if(typeof root == "string"){
-			root = dojo.byId(root);
-			if(!root){
-				return new NodeList([]);
-			}
-		}
-		var results = typeof query == "string" ? engine(query, root) : query.orphan ? query : [query];
-		if(results.orphan){
-			// already wrapped
-			return results; 
-		}
-		return new NodeList(results);
-	};
-	query.matches = engine.match || function(node, selector, root){
-		// summary:
-		//		Test to see if a node matches a selector
-		return query.filter([node], selector, root).length > 0;
-	};
-	// the engine provides a filtering function, use it to for matching
-	query.filter = engine.filter || function(nodes, selector, root){
-		// summary:
-		//		Filters an array of nodes. Note that this does not guarantee to return a dojo.NodeList, just an array.
-		return query(selector, root).filter(function(node){
-			return dojo.indexOf(nodes, node) > -1;
-		});
-	};
-	if(typeof engine != "function"){
-		var search = engine.search;
-		engine = function(selector, root){
-			// Slick does it backwards (or everyone else does it backwards, probably the latter)
-			return search(root || document, selector);
-		};
-	}
-	return query;
-}
-var query = queryForEngine(defaultEngine, NodeList);
-// the query that is returned from this module is slightly different than dojo.query,
-// because dojo.query has to maintain backwards compatibility with returning a
-// true array which has performance problems. The query returned from the module
-// does not use true arrays, but rather inherits from Array, making it much faster to
-// instantiate.
-dojo.query = queryForEngine(defaultEngine, function(array){
-	// call it without the new operator to invoke the back-compat behavior that returns a true array
-	return NodeList(array);
-});
-
-query.load = /*===== dojo.query.load= ======*/ function(id, parentRequire, loaded, config){
-	// summary: can be used as AMD plugin to conditionally load new query engine
-	// example:
-	//	|	define(["dojo/query!custom"], function(qsa){ 
-	//	|		// loaded selector/custom.js as engine
-	//	|		qsa("#foobar").forEach(...);
-	//	|	});
-	loader.load(id, parentRequire, function(engine){
-		loaded(queryForEngine(engine, NodeList));
-	});
-};
-
-dojo._filterQueryResult = query._filterResult = function(nodes, selector, root){
-	return new NodeList(query.filter(nodes, selector, root));
-};
-dojo.NodeList = query.NodeList = NodeList;
-return query;
-});
+define(["./_base/kernel", "./has", "./on", "./_base/array", "./_base/lang", "./selector/_loader", "./selector/_loader!default"], function(dojo, has, on, array, lang, loader, defaultEngine){
+"use strict";
+
+	has.add("array-extensible", function(){
+		// test to see if we can extend an array (not supported in old IE)
+		return lang.delegate([], {length: 1}).length == 1 && !has("bug-for-in-skips-shadowed");
+	});
+	
+	var ap = Array.prototype, aps = ap.slice, apc = ap.concat, forEach = array.forEach;
+
+	var tnl = function(/*Array*/ a, /*dojo.NodeList?*/ parent, /*Function?*/ NodeListCtor){
+		// summary:
+		//		decorate an array to make it look like a `dojo.NodeList`.
+		// a:
+		//		Array of nodes to decorate.
+		// parent:
+		//		An optional parent NodeList that generated the current
+		//		list of nodes. Used to call _stash() so the parent NodeList
+		//		can be accessed via end() later.
+		// NodeListCtor:
+		//		An optional constructor function to use for any
+		//		new NodeList calls. This allows a certain chain of
+		//		NodeList calls to use a different object than dojo.NodeList.
+		var nodeList = new (NodeListCtor || this._NodeListCtor || nl)(a);
+		return parent ? nodeList._stash(parent) : nodeList;
+	};
+
+	var loopBody = function(f, a, o){
+		a = [0].concat(aps.call(a, 0));
+		o = o || dojo.global;
+		return function(node){
+			a[0] = node;
+			return f.apply(o, a);
+		};
+	};
+
+	// adapters
+
+	var adaptAsForEach = function(f, o){
+		// summary:
+		//		adapts a single node function to be used in the forEach-type
+		//		actions. The initial object is returned from the specialized
+		//		function.
+		// f: Function
+		//		a function to adapt
+		// o: Object?
+		//		an optional context for f
+		return function(){
+			this.forEach(loopBody(f, arguments, o));
+			return this;	// Object
+		};
+	};
+
+	var adaptAsMap = function(f, o){
+		// summary:
+		//		adapts a single node function to be used in the map-type
+		//		actions. The return is a new array of values, as via `dojo.map`
+		// f: Function
+		//		a function to adapt
+		// o: Object?
+		//		an optional context for f
+		return function(){
+			return this.map(loopBody(f, arguments, o));
+		};
+	};
+
+	var adaptAsFilter = function(f, o){
+		// summary:
+		//		adapts a single node function to be used in the filter-type actions
+		// f: Function
+		//		a function to adapt
+		// o: Object?
+		//		an optional context for f
+		return function(){
+			return this.filter(loopBody(f, arguments, o));
+		};
+	};
+
+	var adaptWithCondition = function(f, g, o){
+		// summary:
+		//		adapts a single node function to be used in the map-type
+		//		actions, behaves like forEach() or map() depending on arguments
+		// f: Function
+		//		a function to adapt
+		// g: Function
+		//		a condition function, if true runs as map(), otherwise runs as forEach()
+		// o: Object?
+		//		an optional context for f and g
+		return function(){
+			var a = arguments, body = loopBody(f, a, o);
+			if(g.call(o || dojo.global, a)){
+				return this.map(body);	// self
+			}
+			this.forEach(body);
+			return this;	// self
+		};
+	};
+
+	var NodeList = function(array){
+		// summary:
+		//		dojo.NodeList is an of Array-like object which adds syntactic
+		//		sugar for chaining, common iteration operations, animation, and
+		//		node manipulation. NodeLists are most often returned as the
+		//		result of dojo.query() calls.
+		// description:
+		//		dojo.NodeList instances provide many utilities that reflect
+		//		core Dojo APIs for Array iteration and manipulation, DOM
+		//		manipulation, and event handling. Instead of needing to dig up
+		//		functions in the dojo.* namespace, NodeLists generally make the
+		//		full power of Dojo available for DOM manipulation tasks in a
+		//		simple, chainable way.
+		// example:
+		//		create a node list from a node
+		//		|	new dojo.NodeList(dojo.byId("foo"));
+		// example:
+		//		get a NodeList from a CSS query and iterate on it
+		//		|	var l = dojo.query(".thinger");
+		//		|	l.forEach(function(node, index, nodeList){
+		//		|		console.log(index, node.innerHTML);
+		//		|	});
+		// example:
+		//		use native and Dojo-provided array methods to manipulate a
+		//		NodeList without needing to use dojo.* functions explicitly:
+		//		|	var l = dojo.query(".thinger");
+		//		|	// since NodeLists are real arrays, they have a length
+		//		|	// property that is both readable and writable and
+		//		|	// push/pop/shift/unshift methods
+		//		|	console.log(l.length);
+		//		|	l.push(dojo.create("span"));
+		//		|
+		//		|	// dojo's normalized array methods work too:
+		//		|	console.log( l.indexOf(dojo.byId("foo")) );
+		//		|	// ...including the special "function as string" shorthand
+		//		|	console.log( l.every("item.nodeType == 1") );
+		//		|
+		//		|	// NodeLists can be [..] indexed, or you can use the at()
+		//		|	// function to get specific items wrapped in a new NodeList:
+		//		|	var node = l[3]; // the 4th element
+		//		|	var newList = l.at(1, 3); // the 2nd and 4th elements
+		// example:
+		//		the style functions you expect are all there too:
+		//		|	// style() as a getter...
+		//		|	var borders = dojo.query(".thinger").style("border");
+		//		|	// ...and as a setter:
+		//		|	dojo.query(".thinger").style("border", "1px solid black");
+		//		|	// class manipulation
+		//		|	dojo.query("li:nth-child(even)").addClass("even");
+		//		|	// even getting the coordinates of all the items
+		//		|	var coords = dojo.query(".thinger").coords();
+		// example:
+		//		DOM manipulation functions from the dojo.* namespace area also
+		//		available:
+		//		|	// remove all of the elements in the list from their
+		//		|	// parents (akin to "deleting" them from the document)
+		//		|	dojo.query(".thinger").orphan();
+		//		|	// place all elements in the list at the front of #foo
+		//		|	dojo.query(".thinger").place("foo", "first");
+		// example:
+		//		Event handling couldn't be easier. `dojo.connect` is mapped in,
+		//		and shortcut handlers are provided for most DOM events:
+		//		|	// like dojo.connect(), but with implicit scope
+		//		|	dojo.query("li").connect("onclick", console, "log");
+		//		|
+		//		|	// many common event handlers are already available directly:
+		//		|	dojo.query("li").onclick(console, "log");
+		//		|	var toggleHovered = dojo.hitch(dojo, "toggleClass", "hovered");
+		//		|	dojo.query("p")
+		//		|		.onmouseenter(toggleHovered)
+		//		|		.onmouseleave(toggleHovered);
+		// example:
+		//		chainability is a key advantage of NodeLists:
+		//		|	dojo.query(".thinger")
+		//		|		.onclick(function(e){ /* ... */ })
+		//		|		.at(1, 3, 8) // get a subset
+		//		|			.style("padding", "5px")
+		//		|			.forEach(console.log);
+		var isNew = this instanceof nl && has("array-extensible");
+		if(typeof array == "number"){
+			array = Array(array);
+		}
+		var nodeArray = (array && "length" in array) ? array : arguments;
+		if(isNew || !nodeArray.sort){
+			// make sure it's a real array before we pass it on to be wrapped 
+			var target = isNew ? this : [],
+				l = target.length = nodeArray.length;
+			for(var i = 0; i < l; i++){
+				target[i] = nodeArray[i];
+			}
+			if(isNew){
+				// called with new operator, this means we are going to use this instance and push
+				// the nodes on to it. This is usually much faster since the NodeList properties
+				//	don't need to be copied (unless the list of nodes is extremely large).
+				return target;
+			}
+			nodeArray = target;
+		}
+		// called without new operator, use a real array and copy prototype properties,
+		// this is slower and exists for back-compat. Should be removed in 2.0.
+		lang._mixin(nodeArray, nlp);
+		nodeArray._NodeListCtor = function(array){
+			// call without new operator to preserve back-compat behavior
+			return nl(array);
+		}
+		return nodeArray;
+	};
+	
+	var nl = NodeList, nlp = nl.prototype = 
+		has("array-extensible") ? [] : {};// extend an array if it is extensible
+
+	// expose adapters and the wrapper as private functions
+
+	nl._wrap = nlp._wrap = tnl;
+	nl._adaptAsMap = adaptAsMap;
+	nl._adaptAsForEach = adaptAsForEach;
+	nl._adaptAsFilter  = adaptAsFilter;
+	nl._adaptWithCondition = adaptWithCondition;
+
+	// mass assignment
+
+	// add array redirectors
+	forEach(["slice", "splice"], function(name){
+		var f = ap[name];
+		//Use a copy of the this array via this.slice() to allow .end() to work right in the splice case.
+		// CANNOT apply ._stash()/end() to splice since it currently modifies
+		// the existing this array -- it would break backward compatibility if we copy the array before
+		// the splice so that we can use .end(). So only doing the stash option to this._wrap for slice.
+		nlp[name] = function(){ return this._wrap(f.apply(this, arguments), name == "slice" ? this : null); };
+	});
+	// concat should be here but some browsers with native NodeList have problems with it
+
+	// add array.js redirectors
+	forEach(["indexOf", "lastIndexOf", "every", "some"], function(name){
+		var f = array[name];
+		nlp[name] = function(){ return f.apply(dojo, [this].concat(aps.call(arguments, 0))); };
+	});
+
+	/*===== var NodeList = dojo.NodeList; =====*/
+	lang.extend(NodeList, {
+		// copy the constructors
+		constructor: nl,
+		_NodeListCtor: nl,
+		toString: function(){
+			// Array.prototype.toString can't be applied to objects, so we use join
+			return this.join(",");
+		},
+		_stash: function(parent){
+			// summary:
+			//		private function to hold to a parent NodeList. end() to return the parent NodeList.
+			//
+			// example:
+			// How to make a `dojo.NodeList` method that only returns the third node in
+			// the dojo.NodeList but allows access to the original NodeList by using this._stash:
+			//	|	dojo.extend(dojo.NodeList, {
+			//	|		third: function(){
+			//	|			var newNodeList = dojo.NodeList(this[2]);
+			//	|			return newNodeList._stash(this);
+			//	|		}
+			//	|	});
+			//	|	// then see how _stash applies a sub-list, to be .end()'ed out of
+			//	|	dojo.query(".foo")
+			//	|		.third()
+			//	|			.addClass("thirdFoo")
+			//	|		.end()
+			//	|		// access to the orig .foo list
+			//	|		.removeClass("foo")
+			//	|
+			//
+			this._parent = parent;
+			return this; //dojo.NodeList
+		},
+
+		on: function(eventName, listener){
+			// summary:
+			//		Listen for events on the nodes in the NodeList. Basic usage is:
+			//		| query(".my-class").on("click", listener);
+			// 		This supports event delegation by using selectors as the first argument with the event names as
+			//		pseudo selectors. For example:
+			//		| dojo.query("#my-list").on("li:click", listener);
+			//		This will listen for click events within <li> elements that are inside the #my-list element.
+			//		Because on supports CSS selector syntax, we can use comma-delimited events as well:
+			//		| dojo.query("#my-list").on("li button:mouseover, li:click", listener);
+			var handles = this.map(function(node){
+				return on(node, eventName, listener); // TODO: apply to the NodeList so the same selector engine is used for matches
+			});
+			handles.remove = function(){
+				for(var i = 0; i < handles.length; i++){
+					handles[i].remove();
+				}
+			};
+			return handles;
+		},
+
+		end: function(){
+			// summary:
+			//		Ends use of the current `dojo.NodeList` by returning the previous dojo.NodeList
+			//		that generated the current dojo.NodeList.
+			// description:
+			//		Returns the `dojo.NodeList` that generated the current `dojo.NodeList`. If there
+			//		is no parent dojo.NodeList, an empty dojo.NodeList is returned.
+			// example:
+			//	|	dojo.query("a")
+			//	|		.filter(".disabled")
+			//	|			// operate on the anchors that only have a disabled class
+			//	|			.style("color", "grey")
+			//	|		.end()
+			//	|		// jump back to the list of anchors
+			//	|		.style(...)
+			//
+			if(this._parent){
+				return this._parent;
+			}else{
+				//Just return empty list.
+				return new this._NodeListCtor(0);
+			}
+		},
+
+		// http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array#Methods
+
+		// FIXME: handle return values for #3244
+		//		http://trac.dojotoolkit.org/ticket/3244
+
+		// FIXME:
+		//		need to wrap or implement:
+		//			join (perhaps w/ innerHTML/outerHTML overload for toString() of items?)
+		//			reduce
+		//			reduceRight
+
+		/*=====
+		slice: function(begin, end){
+			// summary:
+			//		Returns a new NodeList, maintaining this one in place
+			// description:
+			//		This method behaves exactly like the Array.slice method
+			//		with the caveat that it returns a dojo.NodeList and not a
+			//		raw Array. For more details, see Mozilla's (slice
+			//		documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:slice]
+			// begin: Integer
+			//		Can be a positive or negative integer, with positive
+			//		integers noting the offset to begin at, and negative
+			//		integers denoting an offset from the end (i.e., to the left
+			//		of the end)
+			// end: Integer?
+			//		Optional parameter to describe what position relative to
+			//		the NodeList's zero index to end the slice at. Like begin,
+			//		can be positive or negative.
+			return this._wrap(a.slice.apply(this, arguments));
+		},
+
+		splice: function(index, howmany, item){
+			// summary:
+			//		Returns a new NodeList, manipulating this NodeList based on
+			//		the arguments passed, potentially splicing in new elements
+			//		at an offset, optionally deleting elements
+			// description:
+			//		This method behaves exactly like the Array.splice method
+			//		with the caveat that it returns a dojo.NodeList and not a
+			//		raw Array. For more details, see Mozilla's (splice
+			//		documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:splice]
+			//		For backwards compatibility, calling .end() on the spliced NodeList
+			//		does not return the original NodeList -- splice alters the NodeList in place.
+			// index: Integer
+			//		begin can be a positive or negative integer, with positive
+			//		integers noting the offset to begin at, and negative
+			//		integers denoting an offset from the end (i.e., to the left
+			//		of the end)
+			// howmany: Integer?
+			//		Optional parameter to describe what position relative to
+			//		the NodeList's zero index to end the slice at. Like begin,
+			//		can be positive or negative.
+			// item: Object...?
+			//		Any number of optional parameters may be passed in to be
+			//		spliced into the NodeList
+			// returns:
+			//		dojo.NodeList
+			return this._wrap(a.splice.apply(this, arguments));
+		},
+
+		indexOf: function(value, fromIndex){
+			// summary:
+			//		see dojo.indexOf(). The primary difference is that the acted-on
+			//		array is implicitly this NodeList
+			// value: Object:
+			//		The value to search for.
+			// fromIndex: Integer?:
+			//		The location to start searching from. Optional. Defaults to 0.
+			// description:
+			//		For more details on the behavior of indexOf, see Mozilla's
+			//		(indexOf
+			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf]
+			// returns:
+			//		Positive Integer or 0 for a match, -1 of not found.
+			return d.indexOf(this, value, fromIndex); // Integer
+		},
+
+		lastIndexOf: function(value, fromIndex){
+			// summary:
+			//		see dojo.lastIndexOf(). The primary difference is that the
+			//		acted-on array is implicitly this NodeList
+			// description:
+			//		For more details on the behavior of lastIndexOf, see
+			//		Mozilla's (lastIndexOf
+			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf]
+			// value: Object
+			//		The value to search for.
+			// fromIndex: Integer?
+			//		The location to start searching from. Optional. Defaults to 0.
+			// returns:
+			//		Positive Integer or 0 for a match, -1 of not found.
+			return d.lastIndexOf(this, value, fromIndex); // Integer
+		},
+
+		every: function(callback, thisObject){
+			// summary:
+			//		see `dojo.every()` and the (Array.every
+			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:every].
+			//		Takes the same structure of arguments and returns as
+			//		dojo.every() with the caveat that the passed array is
+			//		implicitly this NodeList
+			// callback: Function: the callback
+			// thisObject: Object?: the context
+			return d.every(this, callback, thisObject); // Boolean
+		},
+
+		some: function(callback, thisObject){
+			// summary:
+			//		Takes the same structure of arguments and returns as
+			//		`dojo.some()` with the caveat that the passed array is
+			//		implicitly this NodeList.  See `dojo.some()` and Mozilla's
+			//		(Array.some
+			//		documentation)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:some].
+			// callback: Function: the callback
+			// thisObject: Object?: the context
+			return d.some(this, callback, thisObject); // Boolean
+		},
+		=====*/
+
+		concat: function(item){
+			// summary:
+			//		Returns a new NodeList comprised of items in this NodeList
+			//		as well as items passed in as parameters
+			// description:
+			//		This method behaves exactly like the Array.concat method
+			//		with the caveat that it returns a `dojo.NodeList` and not a
+			//		raw Array. For more details, see the (Array.concat
+			//		docs)[http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:concat]
+			// item: Object?
+			//		Any number of optional parameters may be passed in to be
+			//		spliced into the NodeList
+			// returns:
+			//		dojo.NodeList
+
+			//return this._wrap(apc.apply(this, arguments));
+			// the line above won't work for the native NodeList :-(
+
+			// implementation notes:
+			// 1) Native NodeList is not an array, and cannot be used directly
+			// in concat() --- the latter doesn't recognize it as an array, and
+			// does not inline it, but append as a single entity.
+			// 2) On some browsers (e.g., Safari) the "constructor" property is
+			// read-only and cannot be changed. So we have to test for both
+			// native NodeList and dojo.NodeList in this property to recognize
+			// the node list.
+
+			var t = lang.isArray(this) ? this : aps.call(this, 0),
+				m = array.map(arguments, function(a){
+					return a && !lang.isArray(a) &&
+						(typeof NodeList != "undefined" && a.constructor === NodeList || a.constructor === this._NodeListCtor) ?
+							aps.call(a, 0) : a;
+				});
+			return this._wrap(apc.apply(t, m), this);	// dojo.NodeList
+		},
+
+		map: function(/*Function*/ func, /*Function?*/ obj){
+			// summary:
+			//		see dojo.map(). The primary difference is that the acted-on
+			//		array is implicitly this NodeList and the return is a
+			//		dojo.NodeList (a subclass of Array)
+			///return d.map(this, func, obj, d.NodeList); // dojo.NodeList
+			return this._wrap(array.map(this, func, obj), this); // dojo.NodeList
+		},
+
+		forEach: function(callback, thisObj){
+			// summary:
+			//		see `dojo.forEach()`. The primary difference is that the acted-on
+			//		array is implicitly this NodeList. If you want the option to break out
+			//		of the forEach loop, use every() or some() instead.
+			forEach(this, callback, thisObj);
+			// non-standard return to allow easier chaining
+			return this; // dojo.NodeList
+		},
+		filter: function(/*String|Function*/ filter){
+			// summary:
+			//		"masks" the built-in javascript filter() method (supported
+			//		in Dojo via `dojo.filter`) to support passing a simple
+			//		string filter in addition to supporting filtering function
+			//		objects.
+			// filter:
+			//		If a string, a CSS rule like ".thinger" or "div > span".
+			// example:
+			//		"regular" JS filter syntax as exposed in dojo.filter:
+			//		|	dojo.query("*").filter(function(item){
+			//		|		// highlight every paragraph
+			//		|		return (item.nodeName == "p");
+			//		|	}).style("backgroundColor", "yellow");
+			// example:
+			//		the same filtering using a CSS selector
+			//		|	dojo.query("*").filter("p").styles("backgroundColor", "yellow");
+
+			var a = arguments, items = this, start = 0;
+			if(typeof filter == "string"){ // inline'd type check
+				items = query._filterResult(this, a[0]);
+				if(a.length == 1){
+					// if we only got a string query, pass back the filtered results
+					return items._stash(this); // dojo.NodeList
+				}
+				// if we got a callback, run it over the filtered items
+				start = 1;
+			}
+			return this._wrap(array.filter(items, a[start], a[start + 1]), this);	// dojo.NodeList
+		},
+		instantiate: function(/*String|Object*/ declaredClass, /*Object?*/ properties){
+			// summary:
+			//		Create a new instance of a specified class, using the
+			//		specified properties and each node in the nodeList as a
+			//		srcNodeRef.
+			// example:
+			//		Grabs all buttons in the page and converts them to diji.form.Buttons.
+			//	|	var buttons = dojo.query("button").instantiate("dijit.form.Button", {showLabel: true});
+			var c = lang.isFunction(declaredClass) ? declaredClass : lang.getObject(declaredClass);
+			properties = properties || {};
+			return this.forEach(function(node){
+				new c(properties, node);
+			});	// dojo.NodeList
+		},
+		at: function(/*===== index =====*/){
+			// summary:
+			//		Returns a new NodeList comprised of items in this NodeList
+			//		at the given index or indices.
+			//
+			// index: Integer...
+			//		One or more 0-based indices of items in the current
+			//		NodeList. A negative index will start at the end of the
+			//		list and go backwards.
+			//
+			// example:
+			//	Shorten the list to the first, second, and third elements
+			//	|	dojo.query("a").at(0, 1, 2).forEach(fn);
+			//
+			// example:
+			//	Retrieve the first and last elements of a unordered list:
+			//	|	dojo.query("ul > li").at(0, -1).forEach(cb);
+			//
+			// example:
+			//	Do something for the first element only, but end() out back to
+			//	the original list and continue chaining:
+			//	|	dojo.query("a").at(0).onclick(fn).end().forEach(function(n){
+			//	|		console.log(n); // all anchors on the page.
+			//	|	})
+			//
+			// returns:
+			//		dojo.NodeList
+			var t = new this._NodeListCtor(0);
+			forEach(arguments, function(i){
+				if(i < 0){ i = this.length + i; }
+				if(this[i]){ t.push(this[i]); }
+			}, this);
+			return t._stash(this); // dojo.NodeList
+		}
+	});
+
+
+/*===== 
+dojo.query = function(selector, context){
+	// summary:
+	//		This modules provides DOM querying functionality. The module export is a function
+	//		that can be used to query for DOM nodes by CSS selector and returns a dojo.NodeList
+	//		representing the matching nodes.
+	//
+	// selector: String
+	//		A CSS selector to search for.
+	// context: String|DomNode?
+	//		An optional context to limit the searching scope. Only nodes under `context` will be 
+	//		scanned. 
+	// 
+	//	example:
+	//		add an onclick handler to every submit button in the document
+	//		which causes the form to be sent via Ajax instead:
+	//	|	define(["dojo/query"], function(query){
+	// 	|	query("input[type='submit']").on("click", function(e){
+	//	|		dojo.stopEvent(e); // prevent sending the form
+	//	|		var btn = e.target;
+	//	|		dojo.xhrPost({
+	//	|			form: btn.form,
+	//	|			load: function(data){
+	//	|				// replace the form with the response
+	//	|				var div = dojo.doc.createElement("div");
+	//	|				dojo.place(div, btn.form, "after");
+	//	|				div.innerHTML = data;
+	//	|				dojo.style(btn.form, "display", "none");
+	//	|			}
+	//	|		});
+	//	|	}); 
+	//
+	// description:
+	//		dojo/query is responsible for loading the appropriate query engine and wrapping 
+	//		its results with a `dojo.NodeList`. You can use dojo/query with a specific selector engine
+	//		by using it as a plugin. For example, if you installed the sizzle package, you could
+	//		use it as the selector engine with:
+	//		|	define("dojo/query!sizzle", function(query){
+	//		|		query("div")...
+	//
+	//		The id after the ! can be a module id of the selector engine or one of the following values:
+	//		|	+ acme: This is the default engine used by Dojo base, and will ensure that the full
+	//		|	Acme engine is always loaded. 
+	//		|	
+	//		|	+ css2: If the browser has a native selector engine, this will be used, otherwise a
+	//		|	very minimal lightweight selector engine will be loaded that can do simple CSS2 selectors
+	//		|	(by #id, .class, tag, and [name=value] attributes, with standard child or descendant (>)
+	//		|	operators) and nothing more.
+	//		|
+	//		|	+ css2.1: If the browser has a native selector engine, this will be used, otherwise the
+	//		|	full Acme engine will be loaded. 
+	//		|	
+	//		|	+ css3: If the browser has a native selector engine with support for CSS3 pseudo
+	//		|	selectors (most modern browsers except IE8), this will be used, otherwise the
+	//		|	full Acme engine will be loaded.
+	//		|	
+	//		|	+ Or the module id of a selector engine can be used to explicitly choose the selector engine
+	//		
+	//		For example, if you are using CSS3 pseudo selectors in module, you can specify that
+	//		you will need support them with:
+	//		|	define("dojo/query!css3", function(query){
+	//		|		query('#t > h3:nth-child(odd)')...
+	//
+	//		You can also choose the selector engine/load configuration by setting the <FIXME:what is the configuration setting?>.
+	//		For example:
+	//		|	<script data-dojo-config="query-selector:'css3'" src="dojo.js"></script>
+	//		
+	return new dojo.NodeList(); // dojo.NodeList
+};
+=====*/
+
+function queryForEngine(engine, NodeList){
+	var query = function(/*String*/ query, /*String|DOMNode?*/ root){
+		//	summary:
+		//		Returns nodes which match the given CSS selector, searching the
+		//		entire document by default but optionally taking a node to scope
+		//		the search by. Returns an instance of dojo.NodeList.
+		if(typeof root == "string"){
+			root = dojo.byId(root);
+			if(!root){
+				return new NodeList([]);
+			}
+		}
+		var results = typeof query == "string" ? engine(query, root) : query.orphan ? query : [query];
+		if(results.orphan){
+			// already wrapped
+			return results; 
+		}
+		return new NodeList(results);
+	};
+	query.matches = engine.match || function(node, selector, root){
+		// summary:
+		//		Test to see if a node matches a selector
+		return query.filter([node], selector, root).length > 0;
+	};
+	// the engine provides a filtering function, use it to for matching
+	query.filter = engine.filter || function(nodes, selector, root){
+		// summary:
+		//		Filters an array of nodes. Note that this does not guarantee to return a dojo.NodeList, just an array.
+		return query(selector, root).filter(function(node){
+			return dojo.indexOf(nodes, node) > -1;
+		});
+	};
+	if(typeof engine != "function"){
+		var search = engine.search;
+		engine = function(selector, root){
+			// Slick does it backwards (or everyone else does it backwards, probably the latter)
+			return search(root || document, selector);
+		};
+	}
+	return query;
+}
+var query = queryForEngine(defaultEngine, NodeList);
+// the query that is returned from this module is slightly different than dojo.query,
+// because dojo.query has to maintain backwards compatibility with returning a
+// true array which has performance problems. The query returned from the module
+// does not use true arrays, but rather inherits from Array, making it much faster to
+// instantiate.
+dojo.query = queryForEngine(defaultEngine, function(array){
+	// call it without the new operator to invoke the back-compat behavior that returns a true array
+	return NodeList(array);
+});
+
+query.load = /*===== dojo.query.load= ======*/ function(id, parentRequire, loaded, config){
+	// summary: can be used as AMD plugin to conditionally load new query engine
+	// example:
+	//	|	define(["dojo/query!custom"], function(qsa){ 
+	//	|		// loaded selector/custom.js as engine
+	//	|		qsa("#foobar").forEach(...);
+	//	|	});
+	loader.load(id, parentRequire, function(engine){
+		loaded(queryForEngine(engine, NodeList));
+	});
+};
+
+dojo._filterQueryResult = query._filterResult = function(nodes, selector, root){
+	return new NodeList(query.filter(nodes, selector, root));
+};
+dojo.NodeList = query.NodeList = NodeList;
+return query;
+});
diff --git a/selector/_loader.js b/selector/_loader.js
index a8d233b..e5c9094 100644
--- a/selector/_loader.js
+++ b/selector/_loader.js
@@ -1,45 +1,45 @@
-define(["../has", "require"],
-		function(has, require){
-// summary:
-//		This module handles loading the appropriate selector engine for the given browser
-"use strict";
-var testDiv = document.createElement("div");
-has.add("dom-qsa2.1", !!testDiv.querySelectorAll);
-has.add("dom-qsa3", function(){
-			// test to see if we have a reasonable native selector engine available
-			try{
-				testDiv.innerHTML = "<p class='TEST'></p>"; // test kind of from sizzle
-				// Safari can't handle uppercase or unicode characters when
-				// in quirks mode, IE8 can't handle pseudos like :empty
-				return testDiv.querySelectorAll(".TEST:empty").length == 1;
-			}catch(e){}
-		});
-var fullEngine;
-var acme = "./acme", lite = "./lite";
-return {
-	load: function(id, parentRequire, loaded, config){
-		var req = require;
-		// here we implement the default logic for choosing a selector engine
-		id = id == "default" ? has("config-selectorEngine") || "css3" : id;
-		id = id == "css2" || id == "lite" ? lite :
-				id == "css2.1" ? has("dom-qsa2.1") ? lite : acme :
-				id == "css3" ? has("dom-qsa3") ? lite : acme :
-				id == "acme" ? acme : (req = parentRequire) && id;
-		if(id.charAt(id.length-1) == '?'){
-			id = id.substring(0,id.length - 1);
-			var optionalLoad = true;
-		}
-		// the query engine is optional, only load it if a native one is not available or existing one has not been loaded
-		if(optionalLoad && (has("dom-compliant-qsa") || fullEngine)){
-			return loaded(fullEngine);
-		}
-		// load the referenced selector engine
-		req([id], function(engine){
-			if(id != "./lite"){
-				fullEngine = engine;
-			}
-			loaded(engine);
-		});
-	}
-};
-});
+define(["../has", "require"],
+		function(has, require){
+// summary:
+//		This module handles loading the appropriate selector engine for the given browser
+"use strict";
+var testDiv = document.createElement("div");
+has.add("dom-qsa2.1", !!testDiv.querySelectorAll);
+has.add("dom-qsa3", function(){
+			// test to see if we have a reasonable native selector engine available
+			try{
+				testDiv.innerHTML = "<p class='TEST'></p>"; // test kind of from sizzle
+				// Safari can't handle uppercase or unicode characters when
+				// in quirks mode, IE8 can't handle pseudos like :empty
+				return testDiv.querySelectorAll(".TEST:empty").length == 1;
+			}catch(e){}
+		});
+var fullEngine;
+var acme = "./acme", lite = "./lite";
+return {
+	load: function(id, parentRequire, loaded, config){
+		var req = require;
+		// here we implement the default logic for choosing a selector engine
+		id = id == "default" ? has("config-selectorEngine") || "css3" : id;
+		id = id == "css2" || id == "lite" ? lite :
+				id == "css2.1" ? has("dom-qsa2.1") ? lite : acme :
+				id == "css3" ? has("dom-qsa3") ? lite : acme :
+				id == "acme" ? acme : (req = parentRequire) && id;
+		if(id.charAt(id.length-1) == '?'){
+			id = id.substring(0,id.length - 1);
+			var optionalLoad = true;
+		}
+		// the query engine is optional, only load it if a native one is not available or existing one has not been loaded
+		if(optionalLoad && (has("dom-compliant-qsa") || fullEngine)){
+			return loaded(fullEngine);
+		}
+		// load the referenced selector engine
+		req([id], function(engine){
+			if(id != "./lite"){
+				fullEngine = engine;
+			}
+			loaded(engine);
+		});
+	}
+};
+});
diff --git a/selector/acme.js b/selector/acme.js
index 7fade66..d90dc72 100644
--- a/selector/acme.js
+++ b/selector/acme.js
@@ -1,1480 +1,1480 @@
-define(["../_base/kernel", "../has", "../dom", "../_base/sniff", "../_base/array", "../_base/lang", "../_base/window"], function(dojo, has, dom){
-  //  module:
-  //    dojo/selector/acme
-  //  summary:
-  //    This module defines the Acme selector engine
-
-/*
-	acme architectural overview:
-
-		acme is a relatively full-featured CSS3 query library. It is
-		designed to take any valid CSS3 selector and return the nodes matching
-		the selector. To do this quickly, it processes queries in several
-		steps, applying caching where profitable.
-
-		The steps (roughly in reverse order of the way they appear in the code):
-			1.) check to see if we already have a "query dispatcher"
-				- if so, use that with the given parameterization. Skip to step 4.
-			2.) attempt to determine which branch to dispatch the query to:
-				- JS (optimized DOM iteration)
-				- native (FF3.1+, Safari 3.1+, IE 8+)
-			3.) tokenize and convert to executable "query dispatcher"
-				- this is where the lion's share of the complexity in the
-					system lies. In the DOM version, the query dispatcher is
-					assembled as a chain of "yes/no" test functions pertaining to
-					a section of a simple query statement (".blah:nth-child(odd)"
-					but not "div div", which is 2 simple statements). Individual
-					statement dispatchers are cached (to prevent re-definition)
-					as are entire dispatch chains (to make re-execution of the
-					same query fast)
-			4.) the resulting query dispatcher is called in the passed scope
-					(by default the top-level document)
-				- for DOM queries, this results in a recursive, top-down
-					evaluation of nodes based on each simple query section
-				- for native implementations, this may mean working around spec
-					bugs. So be it.
-			5.) matched nodes are pruned to ensure they are unique (if necessary)
-*/
-
-
-	////////////////////////////////////////////////////////////////////////
-	// Toolkit aliases
-	////////////////////////////////////////////////////////////////////////
-
-	// if you are extracting acme for use in your own system, you will
-	// need to provide these methods and properties. No other porting should be
-	// necessary, save for configuring the system to use a class other than
-	// dojo.NodeList as the return instance instantiator
-	var trim = 			dojo.trim;
-	var each = 			dojo.forEach;
-	// 					d.isIE; // float
-	// 					d.isSafari; // float
-	// 					d.isOpera; // float
-	// 					d.isWebKit; // float
-	// 					d.doc ; // document element
-
-	var getDoc = function(){ return dojo.doc; };
-	// NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo
-	var cssCaseBug = ((dojo.isWebKit||dojo.isMozilla) && ((getDoc().compatMode) == "BackCompat"));
-
-	////////////////////////////////////////////////////////////////////////
-	// Global utilities
-	////////////////////////////////////////////////////////////////////////
-
-
-	var specials = ">~+";
-
-	// global thunk to determine whether we should treat the current query as
-	// case sensitive or not. This switch is flipped by the query evaluator
-	// based on the document passed as the context to search.
-	var caseSensitive = false;
-
-	// how high?
-	var yesman = function(){ return true; };
-
-	////////////////////////////////////////////////////////////////////////
-	// Tokenizer
-	////////////////////////////////////////////////////////////////////////
-
-	var getQueryParts = function(query){
-		//	summary:
-		//		state machine for query tokenization
-		//	description:
-		//		instead of using a brittle and slow regex-based CSS parser,
-		//		acme implements an AST-style query representation. This
-		//		representation is only generated once per query. For example,
-		//		the same query run multiple times or under different root nodes
-		//		does not re-parse the selector expression but instead uses the
-		//		cached data structure. The state machine implemented here
-		//		terminates on the last " " (space) character and returns an
-		//		ordered array of query component structures (or "parts"). Each
-		//		part represents an operator or a simple CSS filtering
-		//		expression. The structure for parts is documented in the code
-		//		below.
-
-
-		// NOTE:
-		//		this code is designed to run fast and compress well. Sacrifices
-		//		to readability and maintainability have been made.  Your best
-		//		bet when hacking the tokenizer is to put The Donnas on *really*
-		//		loud (may we recommend their "Spend The Night" release?) and
-		//		just assume you're gonna make mistakes. Keep the unit tests
-		//		open and run them frequently. Knowing is half the battle ;-)
-		if(specials.indexOf(query.slice(-1)) >= 0){
-			// if we end with a ">", "+", or "~", that means we're implicitly
-			// searching all children, so make it explicit
-			query += " * "
-		}else{
-			// if you have not provided a terminator, one will be provided for
-			// you...
-			query += " ";
-		}
-
-		var ts = function(/*Integer*/ s, /*Integer*/ e){
-			// trim and slice.
-
-			// take an index to start a string slice from and an end position
-			// and return a trimmed copy of that sub-string
-			return trim(query.slice(s, e));
-		};
-
-		// the overall data graph of the full query, as represented by queryPart objects
-		var queryParts = [];
-
-
-		// state keeping vars
-		var inBrackets = -1, inParens = -1, inMatchFor = -1,
-			inPseudo = -1, inClass = -1, inId = -1, inTag = -1,
-			lc = "", cc = "", pStart;
-
-		// iteration vars
-		var x = 0, // index in the query
-			ql = query.length,
-			currentPart = null, // data structure representing the entire clause
-			_cp = null; // the current pseudo or attr matcher
-
-		// several temporary variables are assigned to this structure during a
-		// potential sub-expression match:
-		//		attr:
-		//			a string representing the current full attribute match in a
-		//			bracket expression
-		//		type:
-		//			if there's an operator in a bracket expression, this is
-		//			used to keep track of it
-		//		value:
-		//			the internals of parenthetical expression for a pseudo. for
-		//			:nth-child(2n+1), value might be "2n+1"
-
-		var endTag = function(){
-			// called when the tokenizer hits the end of a particular tag name.
-			// Re-sets state variables for tag matching and sets up the matcher
-			// to handle the next type of token (tag or operator).
-			if(inTag >= 0){
-				var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
-				currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
-				inTag = -1;
-			}
-		};
-
-		var endId = function(){
-			// called when the tokenizer might be at the end of an ID portion of a match
-			if(inId >= 0){
-				currentPart.id = ts(inId, x).replace(/\\/g, "");
-				inId = -1;
-			}
-		};
-
-		var endClass = function(){
-			// called when the tokenizer might be at the end of a class name
-			// match. CSS allows for multiple classes, so we augment the
-			// current item with another class in its list
-			if(inClass >= 0){
-				currentPart.classes.push(ts(inClass + 1, x).replace(/\\/g, ""));
-				inClass = -1;
-			}
-		};
-
-		var endAll = function(){
-			// at the end of a simple fragment, so wall off the matches
-			endId();
-			endTag();
-			endClass();
-		};
-
-		var endPart = function(){
-			endAll();
-			if(inPseudo >= 0){
-				currentPart.pseudos.push({ name: ts(inPseudo + 1, x) });
-			}
-			// hint to the selector engine to tell it whether or not it
-			// needs to do any iteration. Many simple selectors don't, and
-			// we can avoid significant construction-time work by advising
-			// the system to skip them
-			currentPart.loops = (
-					currentPart.pseudos.length ||
-					currentPart.attrs.length ||
-					currentPart.classes.length	);
-
-			currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string
-
-
-			// otag/tag are hints to suggest to the system whether or not
-			// it's an operator or a tag. We save a copy of otag since the
-			// tag name is cast to upper-case in regular HTML matches. The
-			// system has a global switch to figure out if the current
-			// expression needs to be case sensitive or not and it will use
-			// otag or tag accordingly
-			currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
-
-			if(currentPart.tag){
-				// if we're in a case-insensitive HTML doc, we likely want
-				// the toUpperCase when matching on element.tagName. If we
-				// do it here, we can skip the string op per node
-				// comparison
-				currentPart.tag = currentPart.tag.toUpperCase();
-			}
-
-			// add the part to the list
-			if(queryParts.length && (queryParts[queryParts.length-1].oper)){
-				// operators are always infix, so we remove them from the
-				// list and attach them to the next match. The evaluator is
-				// responsible for sorting out how to handle them.
-				currentPart.infixOper = queryParts.pop();
-				currentPart.query = currentPart.infixOper.query + " " + currentPart.query;
-				/*
-				console.debug(	"swapping out the infix",
-								currentPart.infixOper,
-								"and attaching it to",
-								currentPart);
-				*/
-			}
-			queryParts.push(currentPart);
-
-			currentPart = null;
-		};
-
-		// iterate over the query, character by character, building up a
-		// list of query part objects
-		for(; lc=cc, cc=query.charAt(x), x < ql; x++){
-			//		cc: the current character in the match
-			//		lc: the last character (if any)
-
-			// someone is trying to escape something, so don't try to match any
-			// fragments. We assume we're inside a literal.
-			if(lc == "\\"){ continue; }
-			if(!currentPart){ // a part was just ended or none has yet been created
-				// NOTE: I hate all this alloc, but it's shorter than writing tons of if's
-				pStart = x;
-				//	rules describe full CSS sub-expressions, like:
-				//		#someId
-				//		.className:first-child
-				//	but not:
-				//		thinger > div.howdy[type=thinger]
-				//	the indidual components of the previous query would be
-				//	split into 3 parts that would be represented a structure
-				//	like:
-				//		[
-				//			{
-				//				query: "thinger",
-				//				tag: "thinger",
-				//			},
-				//			{
-				//				query: "div.howdy[type=thinger]",
-				//				classes: ["howdy"],
-				//				infixOper: {
-				//					query: ">",
-				//					oper: ">",
-				//				}
-				//			},
-				//		]
-				currentPart = {
-					query: null, // the full text of the part's rule
-					pseudos: [], // CSS supports multiple pseud-class matches in a single rule
-					attrs: [],	// CSS supports multi-attribute match, so we need an array
-					classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy
-					tag: null,	// only one tag...
-					oper: null, // ...or operator per component. Note that these wind up being exclusive.
-					id: null,	// the id component of a rule
-					getTag: function(){
-						return (caseSensitive) ? this.otag : this.tag;
-					}
-				};
-
-				// if we don't have a part, we assume we're going to start at
-				// the beginning of a match, which should be a tag name. This
-				// might fault a little later on, but we detect that and this
-				// iteration will still be fine.
-				inTag = x;
-			}
-
-			if(inBrackets >= 0){
-				// look for a the close first
-				if(cc == "]"){ // if we're in a [...] clause and we end, do assignment
-					if(!_cp.attr){
-						// no attribute match was previously begun, so we
-						// assume this is an attribute existence match in the
-						// form of [someAttributeName]
-						_cp.attr = ts(inBrackets+1, x);
-					}else{
-						// we had an attribute already, so we know that we're
-						// matching some sort of value, as in [attrName=howdy]
-						_cp.matchFor = ts((inMatchFor||inBrackets+1), x);
-					}
-					var cmf = _cp.matchFor;
-					if(cmf){
-						// try to strip quotes from the matchFor value. We want
-						// [attrName=howdy] to match the same
-						//	as [attrName = 'howdy' ]
-						if(	(cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
-							_cp.matchFor = cmf.slice(1, -1);
-						}
-					}
-					// end the attribute by adding it to the list of attributes.
-					currentPart.attrs.push(_cp);
-					_cp = null; // necessary?
-					inBrackets = inMatchFor = -1;
-				}else if(cc == "="){
-					// if the last char was an operator prefix, make sure we
-					// record it along with the "=" operator.
-					var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
-					_cp.type = addToCc+cc;
-					_cp.attr = ts(inBrackets+1, x-addToCc.length);
-					inMatchFor = x+1;
-				}
-				// now look for other clause parts
-			}else if(inParens >= 0){
-				// if we're in a parenthetical expression, we need to figure
-				// out if it's attached to a pseudo-selector rule like
-				// :nth-child(1)
-				if(cc == ")"){
-					if(inPseudo >= 0){
-						_cp.value = ts(inParens+1, x);
-					}
-					inPseudo = inParens = -1;
-				}
-			}else if(cc == "#"){
-				// start of an ID match
-				endAll();
-				inId = x+1;
-			}else if(cc == "."){
-				// start of a class match
-				endAll();
-				inClass = x;
-			}else if(cc == ":"){
-				// start of a pseudo-selector match
-				endAll();
-				inPseudo = x;
-			}else if(cc == "["){
-				// start of an attribute match.
-				endAll();
-				inBrackets = x;
-				// provide a new structure for the attribute match to fill-in
-				_cp = {
-					/*=====
-					attr: null, type: null, matchFor: null
-					=====*/
-				};
-			}else if(cc == "("){
-				// we really only care if we've entered a parenthetical
-				// expression if we're already inside a pseudo-selector match
-				if(inPseudo >= 0){
-					// provide a new structure for the pseudo match to fill-in
-					_cp = {
-						name: ts(inPseudo+1, x),
-						value: null
-					};
-					currentPart.pseudos.push(_cp);
-				}
-				inParens = x;
-			}else if(
-				(cc == " ") &&
-				// if it's a space char and the last char is too, consume the
-				// current one without doing more work
-				(lc != cc)
-			){
-				endPart();
-			}
-		}
-		return queryParts;
-	};
-
-
-	////////////////////////////////////////////////////////////////////////
-	// DOM query infrastructure
-	////////////////////////////////////////////////////////////////////////
-
-	var agree = function(first, second){
-		// the basic building block of the yes/no chaining system. agree(f1,
-		// f2) generates a new function which returns the boolean results of
-		// both of the passed functions to a single logical-anded result. If
-		// either are not passed, the other is used exclusively.
-		if(!first){ return second; }
-		if(!second){ return first; }
-
-		return function(){
-			return first.apply(window, arguments) && second.apply(window, arguments);
-		}
-	};
-
-	var getArr = function(i, arr){
-		// helps us avoid array alloc when we don't need it
-		var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ?
-		if(i){ r.push(i); }
-		return r;
-	};
-
-	var _isElement = function(n){ return (1 == n.nodeType); };
-
-	// FIXME: need to coalesce _getAttr with defaultGetter
-	var blank = "";
-	var _getAttr = function(elem, attr){
-		if(!elem){ return blank; }
-		if(attr == "class"){
-			return elem.className || blank;
-		}
-		if(attr == "for"){
-			return elem.htmlFor || blank;
-		}
-		if(attr == "style"){
-			return elem.style.cssText || blank;
-		}
-		return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank;
-	};
-
-	var attrs = {
-		"*=": function(attr, value){
-			return function(elem){
-				// E[foo*="bar"]
-				//		an E element whose "foo" attribute value contains
-				//		the substring "bar"
-				return (_getAttr(elem, attr).indexOf(value)>=0);
-			}
-		},
-		"^=": function(attr, value){
-			// E[foo^="bar"]
-			//		an E element whose "foo" attribute value begins exactly
-			//		with the string "bar"
-			return function(elem){
-				return (_getAttr(elem, attr).indexOf(value)==0);
-			}
-		},
-		"$=": function(attr, value){
-			// E[foo$="bar"]
-			//		an E element whose "foo" attribute value ends exactly
-			//		with the string "bar"
-			return function(elem){
-				var ea = " "+_getAttr(elem, attr);
-				return (ea.lastIndexOf(value)==(ea.length-value.length));
-			}
-		},
-		"~=": function(attr, value){
-			// E[foo~="bar"]
-			//		an E element whose "foo" attribute value is a list of
-			//		space-separated values, one of which is exactly equal
-			//		to "bar"
-
-			// return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
-			var tval = " "+value+" ";
-			return function(elem){
-				var ea = " "+_getAttr(elem, attr)+" ";
-				return (ea.indexOf(tval)>=0);
-			}
-		},
-		"|=": function(attr, value){
-			// E[hreflang|="en"]
-			//		an E element whose "hreflang" attribute has a
-			//		hyphen-separated list of values beginning (from the
-			//		left) with "en"
-			var valueDash = value+"-";
-			return function(elem){
-				var ea = _getAttr(elem, attr);
-				return (
-					(ea == value) ||
-					(ea.indexOf(valueDash)==0)
-				);
-			}
-		},
-		"=": function(attr, value){
-			return function(elem){
-				return (_getAttr(elem, attr) == value);
-			}
-		}
-	};
-
-	// avoid testing for node type if we can. Defining this in the negative
-	// here to avoid negation in the fast path.
-	var _noNES = (typeof getDoc().firstChild.nextElementSibling == "undefined");
-	var _ns = !_noNES ? "nextElementSibling" : "nextSibling";
-	var _ps = !_noNES ? "previousElementSibling" : "previousSibling";
-	var _simpleNodeTest = (_noNES ? _isElement : yesman);
-
-	var _lookLeft = function(node){
-		// look left
-		while(node = node[_ps]){
-			if(_simpleNodeTest(node)){ return false; }
-		}
-		return true;
-	};
-
-	var _lookRight = function(node){
-		// look right
-		while(node = node[_ns]){
-			if(_simpleNodeTest(node)){ return false; }
-		}
-		return true;
-	};
-
-	var getNodeIndex = function(node){
-		var root = node.parentNode;
-		var i = 0,
-			tret = root.children || root.childNodes,
-			ci = (node["_i"]||-1),
-			cl = (root["_l"]||-1);
-
-		if(!tret){ return -1; }
-		var l = tret.length;
-
-		// we calculate the parent length as a cheap way to invalidate the
-		// cache. It's not 100% accurate, but it's much more honest than what
-		// other libraries do
-		if( cl == l && ci >= 0 && cl >= 0 ){
-			// if it's legit, tag and release
-			return ci;
-		}
-
-		// else re-key things
-		root["_l"] = l;
-		ci = -1;
-		for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){
-			if(_simpleNodeTest(te)){
-				te["_i"] = ++i;
-				if(node === te){
-					// NOTE:
-					//	shortcutting the return at this step in indexing works
-					//	very well for benchmarking but we avoid it here since
-					//	it leads to potential O(n^2) behavior in sequential
-					//	getNodexIndex operations on a previously un-indexed
-					//	parent. We may revisit this at a later time, but for
-					//	now we just want to get the right answer more often
-					//	than not.
-					ci = i;
-				}
-			}
-		}
-		return ci;
-	};
-
-	var isEven = function(elem){
-		return !((getNodeIndex(elem)) % 2);
-	};
-
-	var isOdd = function(elem){
-		return ((getNodeIndex(elem)) % 2);
-	};
-
-	var pseudos = {
-		"checked": function(name, condition){
-			return function(elem){
-				return !!("checked" in elem ? elem.checked : elem.selected);
-			}
-		},
-		"first-child": function(){ return _lookLeft; },
-		"last-child": function(){ return _lookRight; },
-		"only-child": function(name, condition){
-			return function(node){
-				return _lookLeft(node) && _lookRight(node);
-			};
-		},
-		"empty": function(name, condition){
-			return function(elem){
-				// DomQuery and jQuery get this wrong, oddly enough.
-				// The CSS 3 selectors spec is pretty explicit about it, too.
-				var cn = elem.childNodes;
-				var cnl = elem.childNodes.length;
-				// if(!cnl){ return true; }
-				for(var x=cnl-1; x >= 0; x--){
-					var nt = cn[x].nodeType;
-					if((nt === 1)||(nt == 3)){ return false; }
-				}
-				return true;
-			}
-		},
-		"contains": function(name, condition){
-			var cz = condition.charAt(0);
-			if( cz == '"' || cz == "'" ){ //remove quote
-				condition = condition.slice(1, -1);
-			}
-			return function(elem){
-				return (elem.innerHTML.indexOf(condition) >= 0);
-			}
-		},
-		"not": function(name, condition){
-			var p = getQueryParts(condition)[0];
-			var ignores = { el: 1 };
-			if(p.tag != "*"){
-				ignores.tag = 1;
-			}
-			if(!p.classes.length){
-				ignores.classes = 1;
-			}
-			var ntf = getSimpleFilterFunc(p, ignores);
-			return function(elem){
-				return (!ntf(elem));
-			}
-		},
-		"nth-child": function(name, condition){
-			var pi = parseInt;
-			// avoid re-defining function objects if we can
-			if(condition == "odd"){
-				return isOdd;
-			}else if(condition == "even"){
-				return isEven;
-			}
-			// FIXME: can we shorten this?
-			if(condition.indexOf("n") != -1){
-				var tparts = condition.split("n", 2);
-				var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1;
-				var idx = tparts[1] ? pi(tparts[1]) : 0;
-				var lb = 0, ub = -1;
-				if(pred > 0){
-					if(idx < 0){
-						idx = (idx % pred) && (pred + (idx % pred));
-					}else if(idx>0){
-						if(idx >= pred){
-							lb = idx - idx % pred;
-						}
-						idx = idx % pred;
-					}
-				}else if(pred<0){
-					pred *= -1;
-					// idx has to be greater than 0 when pred is negative;
-					// shall we throw an error here?
-					if(idx > 0){
-						ub = idx;
-						idx = idx % pred;
-					}
-				}
-				if(pred > 0){
-					return function(elem){
-						var i = getNodeIndex(elem);
-						return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
-					}
-				}else{
-					condition = idx;
-				}
-			}
-			var ncount = pi(condition);
-			return function(elem){
-				return (getNodeIndex(elem) == ncount);
-			}
-		}
-	};
-
-	var defaultGetter = (dojo.isIE && (dojo.isIE < 9 || dojo.isQuirks)) ? function(cond){
-		var clc = cond.toLowerCase();
-		if(clc == "class"){ cond = "className"; }
-		return function(elem){
-			return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
-		}
-	} : function(cond){
-		return function(elem){
-			return (elem && elem.getAttribute && elem.hasAttribute(cond));
-		}
-	};
-
-	var getSimpleFilterFunc = function(query, ignores){
-		// generates a node tester function based on the passed query part. The
-		// query part is one of the structures generated by the query parser
-		// when it creates the query AST. The "ignores" object specifies which
-		// (if any) tests to skip, allowing the system to avoid duplicating
-		// work where it may have already been taken into account by other
-		// factors such as how the nodes to test were fetched in the first
-		// place
-		if(!query){ return yesman; }
-		ignores = ignores||{};
-
-		var ff = null;
-
-		if(!("el" in ignores)){
-			ff = agree(ff, _isElement);
-		}
-
-		if(!("tag" in ignores)){
-			if(query.tag != "*"){
-				ff = agree(ff, function(elem){
-					return (elem && (elem.tagName == query.getTag()));
-				});
-			}
-		}
-
-		if(!("classes" in ignores)){
-			each(query.classes, function(cname, idx, arr){
-				// get the class name
-				/*
-				var isWildcard = cname.charAt(cname.length-1) == "*";
-				if(isWildcard){
-					cname = cname.substr(0, cname.length-1);
-				}
-				// I dislike the regex thing, even if memoized in a cache, but it's VERY short
-				var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
-				*/
-				var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)");
-				ff = agree(ff, function(elem){
-					return re.test(elem.className);
-				});
-				ff.count = idx;
-			});
-		}
-
-		if(!("pseudos" in ignores)){
-			each(query.pseudos, function(pseudo){
-				var pn = pseudo.name;
-				if(pseudos[pn]){
-					ff = agree(ff, pseudos[pn](pn, pseudo.value));
-				}
-			});
-		}
-
-		if(!("attrs" in ignores)){
-			each(query.attrs, function(attr){
-				var matcher;
-				var a = attr.attr;
-				// type, attr, matchFor
-				if(attr.type && attrs[attr.type]){
-					matcher = attrs[attr.type](a, attr.matchFor);
-				}else if(a.length){
-					matcher = defaultGetter(a);
-				}
-				if(matcher){
-					ff = agree(ff, matcher);
-				}
-			});
-		}
-
-		if(!("id" in ignores)){
-			if(query.id){
-				ff = agree(ff, function(elem){
-					return (!!elem && (elem.id == query.id));
-				});
-			}
-		}
-
-		if(!ff){
-			if(!("default" in ignores)){
-				ff = yesman;
-			}
-		}
-		return ff;
-	};
-
-	var _nextSibling = function(filterFunc){
-		return function(node, ret, bag){
-			while(node = node[_ns]){
-				if(_noNES && (!_isElement(node))){ continue; }
-				if(
-					(!bag || _isUnique(node, bag)) &&
-					filterFunc(node)
-				){
-					ret.push(node);
-				}
-				break;
-			}
-			return ret;
-		}
-	};
-
-	var _nextSiblings = function(filterFunc){
-		return function(root, ret, bag){
-			var te = root[_ns];
-			while(te){
-				if(_simpleNodeTest(te)){
-					if(bag && !_isUnique(te, bag)){
-						break;
-					}
-					if(filterFunc(te)){
-						ret.push(te);
-					}
-				}
-				te = te[_ns];
-			}
-			return ret;
-		}
-	};
-
-	// get an array of child *elements*, skipping text and comment nodes
-	var _childElements = function(filterFunc){
-		filterFunc = filterFunc||yesman;
-		return function(root, ret, bag){
-			// get an array of child elements, skipping text and comment nodes
-			var te, x = 0, tret = root.children || root.childNodes;
-			while(te = tret[x++]){
-				if(
-					_simpleNodeTest(te) &&
-					(!bag || _isUnique(te, bag)) &&
-					(filterFunc(te, x))
-				){
-					ret.push(te);
-				}
-			}
-			return ret;
-		};
-	};
-
-	/*
-	// thanks, Dean!
-	var itemIsAfterRoot = d.isIE ? function(item, root){
-		return (item.sourceIndex > root.sourceIndex);
-	} : function(item, root){
-		return (item.compareDocumentPosition(root) == 2);
-	};
-	*/
-
-	// test to see if node is below root
-	var _isDescendant = function(node, root){
-		var pn = node.parentNode;
-		while(pn){
-			if(pn == root){
-				break;
-			}
-			pn = pn.parentNode;
-		}
-		return !!pn;
-	};
-
-	var _getElementsFuncCache = {};
-
-	var getElementsFunc = function(query){
-		var retFunc = _getElementsFuncCache[query.query];
-		// if we've got a cached dispatcher, just use that
-		if(retFunc){ return retFunc; }
-		// else, generate a new on
-
-		// NOTE:
-		//		this function returns a function that searches for nodes and
-		//		filters them.  The search may be specialized by infix operators
-		//		(">", "~", or "+") else it will default to searching all
-		//		descendants (the " " selector). Once a group of children is
-		//		found, a test function is applied to weed out the ones we
-		//		don't want. Many common cases can be fast-pathed. We spend a
-		//		lot of cycles to create a dispatcher that doesn't do more work
-		//		than necessary at any point since, unlike this function, the
-		//		dispatchers will be called every time. The logic of generating
-		//		efficient dispatchers looks like this in pseudo code:
-		//
-		//		# if it's a purely descendant query (no ">", "+", or "~" modifiers)
-		//		if infixOperator == " ":
-		//			if only(id):
-		//				return def(root):
-		//					return d.byId(id, root);
-		//
-		//			elif id:
-		//				return def(root):
-		//					return filter(d.byId(id, root));
-		//
-		//			elif cssClass && getElementsByClassName:
-		//				return def(root):
-		//					return filter(root.getElementsByClassName(cssClass));
-		//
-		//			elif only(tag):
-		//				return def(root):
-		//					return root.getElementsByTagName(tagName);
-		//
-		//			else:
-		//				# search by tag name, then filter
-		//				return def(root):
-		//					return filter(root.getElementsByTagName(tagName||"*"));
-		//
-		//		elif infixOperator == ">":
-		//			# search direct children
-		//			return def(root):
-		//				return filter(root.children);
-		//
-		//		elif infixOperator == "+":
-		//			# search next sibling
-		//			return def(root):
-		//				return filter(root.nextElementSibling);
-		//
-		//		elif infixOperator == "~":
-		//			# search rightward siblings
-		//			return def(root):
-		//				return filter(nextSiblings(root));
-
-		var io = query.infixOper;
-		var oper = (io ? io.oper : "");
-		// the default filter func which tests for all conditions in the query
-		// part. This is potentially inefficient, so some optimized paths may
-		// re-define it to test fewer things.
-		var filterFunc = getSimpleFilterFunc(query, { el: 1 });
-		var qt = query.tag;
-		var wildcardTag = ("*" == qt);
-		var ecs = getDoc()["getElementsByClassName"];
-
-		if(!oper){
-			// if there's no infix operator, then it's a descendant query. ID
-			// and "elements by class name" variants can be accelerated so we
-			// call them out explicitly:
-			if(query.id){
-				// testing shows that the overhead of yesman() is acceptable
-				// and can save us some bytes vs. re-defining the function
-				// everywhere.
-				filterFunc = (!query.loops && wildcardTag) ?
-					yesman :
-					getSimpleFilterFunc(query, { el: 1, id: 1 });
-
-				retFunc = function(root, arr){
-					var te = dom.byId(query.id, (root.ownerDocument||root));
-					if(!te || !filterFunc(te)){ return; }
-					if(9 == root.nodeType){ // if root's a doc, we just return directly
-						return getArr(te, arr);
-					}else{ // otherwise check ancestry
-						if(_isDescendant(te, root)){
-							return getArr(te, arr);
-						}
-					}
-				}
-			}else if(
-				ecs &&
-				// isAlien check. Workaround for Prototype.js being totally evil/dumb.
-				/\{\s*\[native code\]\s*\}/.test(String(ecs)) &&
-				query.classes.length &&
-				!cssCaseBug
-			){
-				// it's a class-based query and we've got a fast way to run it.
-
-				// ignore class and ID filters since we will have handled both
-				filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
-				var classesString = query.classes.join(" ");
-				retFunc = function(root, arr, bag){
-					var ret = getArr(0, arr), te, x=0;
-					var tret = root.getElementsByClassName(classesString);
-					while((te = tret[x++])){
-						if(filterFunc(te, root) && _isUnique(te, bag)){
-							ret.push(te);
-						}
-					}
-					return ret;
-				};
-
-			}else if(!wildcardTag && !query.loops){
-				// it's tag only. Fast-path it.
-				retFunc = function(root, arr, bag){
-					var ret = getArr(0, arr), te, x=0;
-					var tret = root.getElementsByTagName(query.getTag());
-					while((te = tret[x++])){
-						if(_isUnique(te, bag)){
-							ret.push(te);
-						}
-					}
-					return ret;
-				};
-			}else{
-				// the common case:
-				//		a descendant selector without a fast path. By now it's got
-				//		to have a tag selector, even if it's just "*" so we query
-				//		by that and filter
-				filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
-				retFunc = function(root, arr, bag){
-					var ret = getArr(0, arr), te, x=0;
-					// we use getTag() to avoid case sensitivity issues
-					var tret = root.getElementsByTagName(query.getTag());
-					while((te = tret[x++])){
-						if(filterFunc(te, root) && _isUnique(te, bag)){
-							ret.push(te);
-						}
-					}
-					return ret;
-				};
-			}
-		}else{
-			// the query is scoped in some way. Instead of querying by tag we
-			// use some other collection to find candidate nodes
-			var skipFilters = { el: 1 };
-			if(wildcardTag){
-				skipFilters.tag = 1;
-			}
-			filterFunc = getSimpleFilterFunc(query, skipFilters);
-			if("+" == oper){
-				retFunc = _nextSibling(filterFunc);
-			}else if("~" == oper){
-				retFunc = _nextSiblings(filterFunc);
-			}else if(">" == oper){
-				retFunc = _childElements(filterFunc);
-			}
-		}
-		// cache it and return
-		return _getElementsFuncCache[query.query] = retFunc;
-	};
-
-	var filterDown = function(root, queryParts){
-		// NOTE:
-		//		this is the guts of the DOM query system. It takes a list of
-		//		parsed query parts and a root and finds children which match
-		//		the selector represented by the parts
-		var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
-
-		for(var i = 0; i < qpl; i++){
-			ret = [];
-			qp = queryParts[i];
-			x = candidates.length - 1;
-			if(x > 0){
-				// if we have more than one root at this level, provide a new
-				// hash to use for checking group membership but tell the
-				// system not to post-filter us since we will already have been
-				// gauranteed to be unique
-				bag = {};
-				ret.nozip = true;
-			}
-			var gef = getElementsFunc(qp);
-			for(var j = 0; (te = candidates[j]); j++){
-				// for every root, get the elements that match the descendant
-				// selector, adding them to the "ret" array and filtering them
-				// via membership in this level's bag. If there are more query
-				// parts, then this level's return will be used as the next
-				// level's candidates
-				gef(te, ret, bag);
-			}
-			if(!ret.length){ break; }
-			candidates = ret;
-		}
-		return ret;
-	};
-
-	////////////////////////////////////////////////////////////////////////
-	// the query runner
-	////////////////////////////////////////////////////////////////////////
-
-	// these are the primary caches for full-query results. The query
-	// dispatcher functions are generated then stored here for hash lookup in
-	// the future
-	var _queryFuncCacheDOM = {},
-		_queryFuncCacheQSA = {};
-
-	// this is the second level of spliting, from full-length queries (e.g.,
-	// "div.foo .bar") into simple query expressions (e.g., ["div.foo",
-	// ".bar"])
-	var getStepQueryFunc = function(query){
-		var qparts = getQueryParts(trim(query));
-
-		// if it's trivial, avoid iteration and zipping costs
-		if(qparts.length == 1){
-			// we optimize this case here to prevent dispatch further down the
-			// chain, potentially slowing things down. We could more elegantly
-			// handle this in filterDown(), but it's slower for simple things
-			// that need to be fast (e.g., "#someId").
-			var tef = getElementsFunc(qparts[0]);
-			return function(root){
-				var r = tef(root, []);
-				if(r){ r.nozip = true; }
-				return r;
-			}
-		}
-
-		// otherwise, break it up and return a runner that iterates over the parts recursively
-		return function(root){
-			return filterDown(root, qparts);
-		}
-	};
-
-	// NOTES:
-	//	* we can't trust QSA for anything but document-rooted queries, so
-	//	  caching is split into DOM query evaluators and QSA query evaluators
-	//	* caching query results is dirty and leak-prone (or, at a minimum,
-	//	  prone to unbounded growth). Other toolkits may go this route, but
-	//	  they totally destroy their own ability to manage their memory
-	//	  footprint. If we implement it, it should only ever be with a fixed
-	//	  total element reference # limit and an LRU-style algorithm since JS
-	//	  has no weakref support. Caching compiled query evaluators is also
-	//	  potentially problematic, but even on large documents the size of the
-	//	  query evaluators is often < 100 function objects per evaluator (and
-	//	  LRU can be applied if it's ever shown to be an issue).
-	//	* since IE's QSA support is currently only for HTML documents and even
-	//	  then only in IE 8's "standards mode", we have to detect our dispatch
-	//	  route at query time and keep 2 separate caches. Ugg.
-
-	// we need to determine if we think we can run a given query via
-	// querySelectorAll or if we'll need to fall back on DOM queries to get
-	// there. We need a lot of information about the environment and the query
-	// to make the determiniation (e.g. does it support QSA, does the query in
-	// question work in the native QSA impl, etc.).
-	var nua = navigator.userAgent;
-	// some versions of Safari provided QSA, but it was buggy and crash-prone.
-	// We need te detect the right "internal" webkit version to make this work.
-	var wk = "WebKit/";
-	var is525 = (
-		dojo.isWebKit &&
-		(nua.indexOf(wk) > 0) &&
-		(parseFloat(nua.split(wk)[1]) > 528)
-	);
-
-	// IE QSA queries may incorrectly include comment nodes, so we throw the
-	// zipping function into "remove" comments mode instead of the normal "skip
-	// it" which every other QSA-clued browser enjoys
-	var noZip = dojo.isIE ? "commentStrip" : "nozip";
-
-	var qsa = "querySelectorAll";
-	var qsaAvail = (
-		!!getDoc()[qsa] &&
-		// see #5832
-		(!dojo.isSafari || (dojo.isSafari > 3.1) || is525 )
-	);
-
-	//Don't bother with n+3 type of matches, IE complains if we modify those.
-	var infixSpaceRe = /n\+\d|([^ ])?([>~+])([^ =])?/g;
-	var infixSpaceFunc = function(match, pre, ch, post){
-		return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match;
-	};
-
-	var getQueryFunc = function(query, forceDOM){
-		//Normalize query. The CSS3 selectors spec allows for omitting spaces around
-		//infix operators, >, ~ and +
-		//Do the work here since detection for spaces is used as a simple "not use QSA"
-		//test below.
-		query = query.replace(infixSpaceRe, infixSpaceFunc);
-
-		if(qsaAvail){
-			// if we've got a cached variant and we think we can do it, run it!
-			var qsaCached = _queryFuncCacheQSA[query];
-			if(qsaCached && !forceDOM){ return qsaCached; }
-		}
-
-		// else if we've got a DOM cached variant, assume that we already know
-		// all we need to and use it
-		var domCached = _queryFuncCacheDOM[query];
-		if(domCached){ return domCached; }
-
-		// TODO:
-		//		today we're caching DOM and QSA branches separately so we
-		//		recalc useQSA every time. If we had a way to tag root+query
-		//		efficiently, we'd be in good shape to do a global cache.
-
-		var qcz = query.charAt(0);
-		var nospace = (-1 == query.indexOf(" "));
-
-		// byId searches are wicked fast compared to QSA, even when filtering
-		// is required
-		if( (query.indexOf("#") >= 0) && (nospace) ){
-			forceDOM = true;
-		}
-
-		var useQSA = (
-			qsaAvail && (!forceDOM) &&
-			// as per CSS 3, we can't currently start w/ combinator:
-			//		http://www.w3.org/TR/css3-selectors/#w3cselgrammar
-			(specials.indexOf(qcz) == -1) &&
-			// IE's QSA impl sucks on pseudos
-			(!dojo.isIE || (query.indexOf(":") == -1)) &&
-
-			(!(cssCaseBug && (query.indexOf(".") >= 0))) &&
-
-			// FIXME:
-			//		need to tighten up browser rules on ":contains" and "|=" to
-			//		figure out which aren't good
-			//		Latest webkit (around 531.21.8) does not seem to do well with :checked on option
-			//		elements, even though according to spec, selected options should
-			//		match :checked. So go nonQSA for it:
-			//		http://bugs.dojotoolkit.org/ticket/5179
-			(query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) &&
-			(query.indexOf("|=") == -1) // some browsers don't grok it
-		);
-
-		// TODO:
-		//		if we've got a descendant query (e.g., "> .thinger" instead of
-		//		just ".thinger") in a QSA-able doc, but are passed a child as a
-		//		root, it should be possible to give the item a synthetic ID and
-		//		trivially rewrite the query to the form "#synid > .thinger" to
-		//		use the QSA branch
-
-
-		if(useQSA){
-			var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ?
-						(query + " *") : query;
-			return _queryFuncCacheQSA[query] = function(root){
-				try{
-					// the QSA system contains an egregious spec bug which
-					// limits us, effectively, to only running QSA queries over
-					// entire documents.  See:
-					//		http://ejohn.org/blog/thoughts-on-queryselectorall/
-					//	despite this, we can also handle QSA runs on simple
-					//	selectors, but we don't want detection to be expensive
-					//	so we're just checking for the presence of a space char
-					//	right now. Not elegant, but it's cheaper than running
-					//	the query parser when we might not need to
-					if(!((9 == root.nodeType) || nospace)){ throw ""; }
-					var r = root[qsa](tq);
-					// skip expensive duplication checks and just wrap in a NodeList
-					r[noZip] = true;
-					return r;
-				}catch(e){
-					// else run the DOM branch on this query, ensuring that we
-					// default that way in the future
-					return getQueryFunc(query, true)(root);
-				}
-			}
-		}else{
-			// DOM branch
-			var parts = query.split(/\s*,\s*/);
-			return _queryFuncCacheDOM[query] = ((parts.length < 2) ?
-				// if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
-				getStepQueryFunc(query) :
-				// if it *is* a complex query, break it up into its
-				// constituent parts and return a dispatcher that will
-				// merge the parts when run
-				function(root){
-					var pindex = 0, // avoid array alloc for every invocation
-						ret = [],
-						tp;
-					while((tp = parts[pindex++])){
-						ret = ret.concat(getStepQueryFunc(tp)(root));
-					}
-					return ret;
-				}
-			);
-		}
-	};
-
-	var _zipIdx = 0;
-
-	// NOTE:
-	//		this function is Moo inspired, but our own impl to deal correctly
-	//		with XML in IE
-	var _nodeUID = dojo.isIE ? function(node){
-		if(caseSensitive){
-			// XML docs don't have uniqueID on their nodes
-			return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx);
-
-		}else{
-			return node.uniqueID;
-		}
-	} :
-	function(node){
-		return (node._uid || (node._uid = ++_zipIdx));
-	};
-
-	// determine if a node in is unique in a "bag". In this case we don't want
-	// to flatten a list of unique items, but rather just tell if the item in
-	// question is already in the bag. Normally we'd just use hash lookup to do
-	// this for us but IE's DOM is busted so we can't really count on that. On
-	// the upside, it gives us a built in unique ID function.
-	var _isUnique = function(node, bag){
-		if(!bag){ return 1; }
-		var id = _nodeUID(node);
-		if(!bag[id]){ return bag[id] = 1; }
-		return 0;
-	};
-
-	// attempt to efficiently determine if an item in a list is a dupe,
-	// returning a list of "uniques", hopefully in doucment order
-	var _zipIdxName = "_zipIdx";
-	var _zip = function(arr){
-		if(arr && arr.nozip){
-			return arr;
-		}
-		var ret = [];
-		if(!arr || !arr.length){ return ret; }
-		if(arr[0]){
-			ret.push(arr[0]);
-		}
-		if(arr.length < 2){ return ret; }
-
-		_zipIdx++;
-
-		// we have to fork here for IE and XML docs because we can't set
-		// expandos on their nodes (apparently). *sigh*
-		if(dojo.isIE && caseSensitive){
-			var szidx = _zipIdx+"";
-			arr[0].setAttribute(_zipIdxName, szidx);
-			for(var x = 1, te; te = arr[x]; x++){
-				if(arr[x].getAttribute(_zipIdxName) != szidx){
-					ret.push(te);
-				}
-				te.setAttribute(_zipIdxName, szidx);
-			}
-		}else if(dojo.isIE && arr.commentStrip){
-			try{
-				for(var x = 1, te; te = arr[x]; x++){
-					if(_isElement(te)){
-						ret.push(te);
-					}
-				}
-			}catch(e){ /* squelch */ }
-		}else{
-			if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; }
-			for(var x = 1, te; te = arr[x]; x++){
-				if(arr[x][_zipIdxName] != _zipIdx){
-					ret.push(te);
-				}
-				te[_zipIdxName] = _zipIdx;
-			}
-		}
-		return ret;
-	};
-
-	// the main executor
-	var query = function(/*String*/ query, /*String|DOMNode?*/ root){
-		//	summary:
-		//		Returns nodes which match the given CSS3 selector, searching the
-		//		entire document by default but optionally taking a node to scope
-		//		the search by. Returns an array.
-		//	description:
-		//		dojo.query() is the swiss army knife of DOM node manipulation in
-		//		Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
-		//		"$" function, dojo.query provides robust, high-performance
-		//		CSS-based node selector support with the option of scoping searches
-		//		to a particular sub-tree of a document.
-		//
-		//		Supported Selectors:
-		//		--------------------
-		//
-		//		acme supports a rich set of CSS3 selectors, including:
-		//
-		//			* class selectors (e.g., `.foo`)
-		//			* node type selectors like `span`
-		//			* ` ` descendant selectors
-		//			* `>` child element selectors
-		//			* `#foo` style ID selectors
-		//			* `*` universal selector
-		//			* `~`, the preceded-by sibling selector
-		//			* `+`, the immediately preceded-by sibling selector
-		//			* attribute queries:
-		//			|	* `[foo]` attribute presence selector
-		//			|	* `[foo='bar']` attribute value exact match
-		//			|	* `[foo~='bar']` attribute value list item match
-		//			|	* `[foo^='bar']` attribute start match
-		//			|	* `[foo$='bar']` attribute end match
-		//			|	* `[foo*='bar']` attribute substring match
-		//			* `:first-child`, `:last-child`, and `:only-child` positional selectors
-		//			* `:empty` content emtpy selector
-		//			* `:checked` pseudo selector
-		//			* `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
-		//			* `:nth-child(even)`, `:nth-child(odd)` positional selectors
-		//			* `:not(...)` negation pseudo selectors
-		//
-		//		Any legal combination of these selectors will work with
-		//		`dojo.query()`, including compound selectors ("," delimited).
-		//		Very complex and useful searches can be constructed with this
-		//		palette of selectors and when combined with functions for
-		//		manipulation presented by dojo.NodeList, many types of DOM
-		//		manipulation operations become very straightforward.
-		//
-		//		Unsupported Selectors:
-		//		----------------------
-		//
-		//		While dojo.query handles many CSS3 selectors, some fall outside of
-		//		what's reasonable for a programmatic node querying engine to
-		//		handle. Currently unsupported selectors include:
-		//
-		//			* namespace-differentiated selectors of any form
-		//			* all `::` pseduo-element selectors
-		//			* certain pseduo-selectors which don't get a lot of day-to-day use:
-		//			|	* `:root`, `:lang()`, `:target`, `:focus`
-		//			* all visual and state selectors:
-		//			|	* `:root`, `:active`, `:hover`, `:visisted`, `:link`,
-		//				  `:enabled`, `:disabled`
-		//			* `:*-of-type` pseudo selectors
-		//
-		//		dojo.query and XML Documents:
-		//		-----------------------------
-		//
-		//		`dojo.query` (as of dojo 1.2) supports searching XML documents
-		//		in a case-sensitive manner. If an HTML document is served with
-		//		a doctype that forces case-sensitivity (e.g., XHTML 1.1
-		//		Strict), dojo.query() will detect this and "do the right
-		//		thing". Case sensitivity is dependent upon the document being
-		//		searched and not the query used. It is therefore possible to
-		//		use case-sensitive queries on strict sub-documents (iframes,
-		//		etc.) or XML documents while still assuming case-insensitivity
-		//		for a host/root document.
-		//
-		//		Non-selector Queries:
-		//		---------------------
-		//
-		//		If something other than a String is passed for the query,
-		//		`dojo.query` will return a new `dojo.NodeList` instance
-		//		constructed from that parameter alone and all further
-		//		processing will stop. This means that if you have a reference
-		//		to a node or NodeList, you can quickly construct a new NodeList
-		//		from the original by calling `dojo.query(node)` or
-		//		`dojo.query(list)`.
-		//
-		//	query:
-		//		The CSS3 expression to match against. For details on the syntax of
-		//		CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
-		//	root:
-		//		A DOMNode (or node id) to scope the search from. Optional.
-		//	returns: Array
-		//	example:
-		//		search the entire document for elements with the class "foo":
-		//	|	dojo.query(".foo");
-		//		these elements will match:
-		//	|	<span class="foo"></span>
-		//	|	<span class="foo bar"></span>
-		//	|	<p class="thud foo"></p>
-		//	example:
-		//		search the entire document for elements with the classes "foo" *and* "bar":
-		//	|	dojo.query(".foo.bar");
-		//		these elements will match:
-		//	|	<span class="foo bar"></span>
-		//		while these will not:
-		//	|	<span class="foo"></span>
-		//	|	<p class="thud foo"></p>
-		//	example:
-		//		find `<span>` elements which are descendants of paragraphs and
-		//		which have a "highlighted" class:
-		//	|	dojo.query("p span.highlighted");
-		//		the innermost span in this fragment matches:
-		//	|	<p class="foo">
-		//	|		<span>...
-		//	|			<span class="highlighted foo bar">...</span>
-		//	|		</span>
-		//	|	</p>
-		//	example:
-		//		set an "odd" class on all odd table rows inside of the table
-		//		`#tabular_data`, using the `>` (direct child) selector to avoid
-		//		affecting any nested tables:
-		//	|	dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
-		//	example:
-		//		remove all elements with the class "error" from the document
-		//		and store them in a list:
-		//	|	var errors = dojo.query(".error").orphan();
-		//	example:
-		//		add an onclick handler to every submit button in the document
-		//		which causes the form to be sent via Ajax instead:
-		//	|	dojo.query("input[type='submit']").onclick(function(e){
-		//	|		dojo.stopEvent(e); // prevent sending the form
-		//	|		var btn = e.target;
-		//	|		dojo.xhrPost({
-		//	|			form: btn.form,
-		//	|			load: function(data){
-		//	|				// replace the form with the response
-		//	|				var div = dojo.doc.createElement("div");
-		//	|				dojo.place(div, btn.form, "after");
-		//	|				div.innerHTML = data;
-		//	|				dojo.style(btn.form, "display", "none");
-		//	|			}
-		//	|		});
-		//	|	});
-
-		root = root||getDoc();
-		var od = root.ownerDocument||root.documentElement;
-
-		// throw the big case sensitivity switch
-
-		// NOTE:
-		//		Opera in XHTML mode doesn't detect case-sensitivity correctly
-		//		and it's not clear that there's any way to test for it
-		caseSensitive = (root.contentType && root.contentType=="application/xml") ||
-						(dojo.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) ||
-						(!!od) &&
-				(dojo.isIE ? od.xml : (root.xmlVersion || od.xmlVersion));
-
-		// NOTE:
-		//		adding "true" as the 2nd argument to getQueryFunc is useful for
-		//		testing the DOM branch without worrying about the
-		//		behavior/performance of the QSA branch.
-		var r = getQueryFunc(query)(root);
-
-		// FIXME:
-		//		need to investigate this branch WRT #8074 and #8075
-		if(r && r.nozip){
-			return r;
-		}
-		return _zip(r); // dojo.NodeList
-	};
-	query.filter = function(/*Node[]*/ nodeList, /*String*/ filter, /*String|DOMNode?*/ root){
-		// summary:
-		// 		function for filtering a NodeList based on a selector, optimized for simple selectors
-		var tmpNodeList = [],
-			parts = getQueryParts(filter),
-			filterFunc =
-				(parts.length == 1 && !/[^\w#\.]/.test(filter)) ?
-				getSimpleFilterFunc(parts[0]) :
-				function(node){
-					return dojo.query(filter, root).indexOf(node) != -1;
-				};
-		for(var x = 0, te; te = nodeList[x]; x++){
-			if(filterFunc(te)){ tmpNodeList.push(te); }
-		}
-		return tmpNodeList;
-	};
-	return query;
-});//end defineQuery
+define(["../_base/kernel", "../has", "../dom", "../_base/sniff", "../_base/array", "../_base/lang", "../_base/window"], function(dojo, has, dom){
+  //  module:
+  //    dojo/selector/acme
+  //  summary:
+  //    This module defines the Acme selector engine
+
+/*
+	acme architectural overview:
+
+		acme is a relatively full-featured CSS3 query library. It is
+		designed to take any valid CSS3 selector and return the nodes matching
+		the selector. To do this quickly, it processes queries in several
+		steps, applying caching where profitable.
+
+		The steps (roughly in reverse order of the way they appear in the code):
+			1.) check to see if we already have a "query dispatcher"
+				- if so, use that with the given parameterization. Skip to step 4.
+			2.) attempt to determine which branch to dispatch the query to:
+				- JS (optimized DOM iteration)
+				- native (FF3.1+, Safari 3.1+, IE 8+)
+			3.) tokenize and convert to executable "query dispatcher"
+				- this is where the lion's share of the complexity in the
+					system lies. In the DOM version, the query dispatcher is
+					assembled as a chain of "yes/no" test functions pertaining to
+					a section of a simple query statement (".blah:nth-child(odd)"
+					but not "div div", which is 2 simple statements). Individual
+					statement dispatchers are cached (to prevent re-definition)
+					as are entire dispatch chains (to make re-execution of the
+					same query fast)
+			4.) the resulting query dispatcher is called in the passed scope
+					(by default the top-level document)
+				- for DOM queries, this results in a recursive, top-down
+					evaluation of nodes based on each simple query section
+				- for native implementations, this may mean working around spec
+					bugs. So be it.
+			5.) matched nodes are pruned to ensure they are unique (if necessary)
+*/
+
+
+	////////////////////////////////////////////////////////////////////////
+	// Toolkit aliases
+	////////////////////////////////////////////////////////////////////////
+
+	// if you are extracting acme for use in your own system, you will
+	// need to provide these methods and properties. No other porting should be
+	// necessary, save for configuring the system to use a class other than
+	// dojo.NodeList as the return instance instantiator
+	var trim = 			dojo.trim;
+	var each = 			dojo.forEach;
+	// 					d.isIE; // float
+	// 					d.isSafari; // float
+	// 					d.isOpera; // float
+	// 					d.isWebKit; // float
+	// 					d.doc ; // document element
+
+	var getDoc = function(){ return dojo.doc; };
+	// NOTE(alex): the spec is idiotic. CSS queries should ALWAYS be case-sensitive, but nooooooo
+	var cssCaseBug = ((dojo.isWebKit||dojo.isMozilla) && ((getDoc().compatMode) == "BackCompat"));
+
+	////////////////////////////////////////////////////////////////////////
+	// Global utilities
+	////////////////////////////////////////////////////////////////////////
+
+
+	var specials = ">~+";
+
+	// global thunk to determine whether we should treat the current query as
+	// case sensitive or not. This switch is flipped by the query evaluator
+	// based on the document passed as the context to search.
+	var caseSensitive = false;
+
+	// how high?
+	var yesman = function(){ return true; };
+
+	////////////////////////////////////////////////////////////////////////
+	// Tokenizer
+	////////////////////////////////////////////////////////////////////////
+
+	var getQueryParts = function(query){
+		//	summary:
+		//		state machine for query tokenization
+		//	description:
+		//		instead of using a brittle and slow regex-based CSS parser,
+		//		acme implements an AST-style query representation. This
+		//		representation is only generated once per query. For example,
+		//		the same query run multiple times or under different root nodes
+		//		does not re-parse the selector expression but instead uses the
+		//		cached data structure. The state machine implemented here
+		//		terminates on the last " " (space) character and returns an
+		//		ordered array of query component structures (or "parts"). Each
+		//		part represents an operator or a simple CSS filtering
+		//		expression. The structure for parts is documented in the code
+		//		below.
+
+
+		// NOTE:
+		//		this code is designed to run fast and compress well. Sacrifices
+		//		to readability and maintainability have been made.  Your best
+		//		bet when hacking the tokenizer is to put The Donnas on *really*
+		//		loud (may we recommend their "Spend The Night" release?) and
+		//		just assume you're gonna make mistakes. Keep the unit tests
+		//		open and run them frequently. Knowing is half the battle ;-)
+		if(specials.indexOf(query.slice(-1)) >= 0){
+			// if we end with a ">", "+", or "~", that means we're implicitly
+			// searching all children, so make it explicit
+			query += " * "
+		}else{
+			// if you have not provided a terminator, one will be provided for
+			// you...
+			query += " ";
+		}
+
+		var ts = function(/*Integer*/ s, /*Integer*/ e){
+			// trim and slice.
+
+			// take an index to start a string slice from and an end position
+			// and return a trimmed copy of that sub-string
+			return trim(query.slice(s, e));
+		};
+
+		// the overall data graph of the full query, as represented by queryPart objects
+		var queryParts = [];
+
+
+		// state keeping vars
+		var inBrackets = -1, inParens = -1, inMatchFor = -1,
+			inPseudo = -1, inClass = -1, inId = -1, inTag = -1,
+			lc = "", cc = "", pStart;
+
+		// iteration vars
+		var x = 0, // index in the query
+			ql = query.length,
+			currentPart = null, // data structure representing the entire clause
+			_cp = null; // the current pseudo or attr matcher
+
+		// several temporary variables are assigned to this structure during a
+		// potential sub-expression match:
+		//		attr:
+		//			a string representing the current full attribute match in a
+		//			bracket expression
+		//		type:
+		//			if there's an operator in a bracket expression, this is
+		//			used to keep track of it
+		//		value:
+		//			the internals of parenthetical expression for a pseudo. for
+		//			:nth-child(2n+1), value might be "2n+1"
+
+		var endTag = function(){
+			// called when the tokenizer hits the end of a particular tag name.
+			// Re-sets state variables for tag matching and sets up the matcher
+			// to handle the next type of token (tag or operator).
+			if(inTag >= 0){
+				var tv = (inTag == x) ? null : ts(inTag, x); // .toLowerCase();
+				currentPart[ (specials.indexOf(tv) < 0) ? "tag" : "oper" ] = tv;
+				inTag = -1;
+			}
+		};
+
+		var endId = function(){
+			// called when the tokenizer might be at the end of an ID portion of a match
+			if(inId >= 0){
+				currentPart.id = ts(inId, x).replace(/\\/g, "");
+				inId = -1;
+			}
+		};
+
+		var endClass = function(){
+			// called when the tokenizer might be at the end of a class name
+			// match. CSS allows for multiple classes, so we augment the
+			// current item with another class in its list
+			if(inClass >= 0){
+				currentPart.classes.push(ts(inClass + 1, x).replace(/\\/g, ""));
+				inClass = -1;
+			}
+		};
+
+		var endAll = function(){
+			// at the end of a simple fragment, so wall off the matches
+			endId();
+			endTag();
+			endClass();
+		};
+
+		var endPart = function(){
+			endAll();
+			if(inPseudo >= 0){
+				currentPart.pseudos.push({ name: ts(inPseudo + 1, x) });
+			}
+			// hint to the selector engine to tell it whether or not it
+			// needs to do any iteration. Many simple selectors don't, and
+			// we can avoid significant construction-time work by advising
+			// the system to skip them
+			currentPart.loops = (
+					currentPart.pseudos.length ||
+					currentPart.attrs.length ||
+					currentPart.classes.length	);
+
+			currentPart.oquery = currentPart.query = ts(pStart, x); // save the full expression as a string
+
+
+			// otag/tag are hints to suggest to the system whether or not
+			// it's an operator or a tag. We save a copy of otag since the
+			// tag name is cast to upper-case in regular HTML matches. The
+			// system has a global switch to figure out if the current
+			// expression needs to be case sensitive or not and it will use
+			// otag or tag accordingly
+			currentPart.otag = currentPart.tag = (currentPart["oper"]) ? null : (currentPart.tag || "*");
+
+			if(currentPart.tag){
+				// if we're in a case-insensitive HTML doc, we likely want
+				// the toUpperCase when matching on element.tagName. If we
+				// do it here, we can skip the string op per node
+				// comparison
+				currentPart.tag = currentPart.tag.toUpperCase();
+			}
+
+			// add the part to the list
+			if(queryParts.length && (queryParts[queryParts.length-1].oper)){
+				// operators are always infix, so we remove them from the
+				// list and attach them to the next match. The evaluator is
+				// responsible for sorting out how to handle them.
+				currentPart.infixOper = queryParts.pop();
+				currentPart.query = currentPart.infixOper.query + " " + currentPart.query;
+				/*
+				console.debug(	"swapping out the infix",
+								currentPart.infixOper,
+								"and attaching it to",
+								currentPart);
+				*/
+			}
+			queryParts.push(currentPart);
+
+			currentPart = null;
+		};
+
+		// iterate over the query, character by character, building up a
+		// list of query part objects
+		for(; lc=cc, cc=query.charAt(x), x < ql; x++){
+			//		cc: the current character in the match
+			//		lc: the last character (if any)
+
+			// someone is trying to escape something, so don't try to match any
+			// fragments. We assume we're inside a literal.
+			if(lc == "\\"){ continue; }
+			if(!currentPart){ // a part was just ended or none has yet been created
+				// NOTE: I hate all this alloc, but it's shorter than writing tons of if's
+				pStart = x;
+				//	rules describe full CSS sub-expressions, like:
+				//		#someId
+				//		.className:first-child
+				//	but not:
+				//		thinger > div.howdy[type=thinger]
+				//	the indidual components of the previous query would be
+				//	split into 3 parts that would be represented a structure
+				//	like:
+				//		[
+				//			{
+				//				query: "thinger",
+				//				tag: "thinger",
+				//			},
+				//			{
+				//				query: "div.howdy[type=thinger]",
+				//				classes: ["howdy"],
+				//				infixOper: {
+				//					query: ">",
+				//					oper: ">",
+				//				}
+				//			},
+				//		]
+				currentPart = {
+					query: null, // the full text of the part's rule
+					pseudos: [], // CSS supports multiple pseud-class matches in a single rule
+					attrs: [],	// CSS supports multi-attribute match, so we need an array
+					classes: [], // class matches may be additive, e.g.: .thinger.blah.howdy
+					tag: null,	// only one tag...
+					oper: null, // ...or operator per component. Note that these wind up being exclusive.
+					id: null,	// the id component of a rule
+					getTag: function(){
+						return (caseSensitive) ? this.otag : this.tag;
+					}
+				};
+
+				// if we don't have a part, we assume we're going to start at
+				// the beginning of a match, which should be a tag name. This
+				// might fault a little later on, but we detect that and this
+				// iteration will still be fine.
+				inTag = x;
+			}
+
+			if(inBrackets >= 0){
+				// look for a the close first
+				if(cc == "]"){ // if we're in a [...] clause and we end, do assignment
+					if(!_cp.attr){
+						// no attribute match was previously begun, so we
+						// assume this is an attribute existence match in the
+						// form of [someAttributeName]
+						_cp.attr = ts(inBrackets+1, x);
+					}else{
+						// we had an attribute already, so we know that we're
+						// matching some sort of value, as in [attrName=howdy]
+						_cp.matchFor = ts((inMatchFor||inBrackets+1), x);
+					}
+					var cmf = _cp.matchFor;
+					if(cmf){
+						// try to strip quotes from the matchFor value. We want
+						// [attrName=howdy] to match the same
+						//	as [attrName = 'howdy' ]
+						if(	(cmf.charAt(0) == '"') || (cmf.charAt(0) == "'") ){
+							_cp.matchFor = cmf.slice(1, -1);
+						}
+					}
+					// end the attribute by adding it to the list of attributes.
+					currentPart.attrs.push(_cp);
+					_cp = null; // necessary?
+					inBrackets = inMatchFor = -1;
+				}else if(cc == "="){
+					// if the last char was an operator prefix, make sure we
+					// record it along with the "=" operator.
+					var addToCc = ("|~^$*".indexOf(lc) >=0 ) ? lc : "";
+					_cp.type = addToCc+cc;
+					_cp.attr = ts(inBrackets+1, x-addToCc.length);
+					inMatchFor = x+1;
+				}
+				// now look for other clause parts
+			}else if(inParens >= 0){
+				// if we're in a parenthetical expression, we need to figure
+				// out if it's attached to a pseudo-selector rule like
+				// :nth-child(1)
+				if(cc == ")"){
+					if(inPseudo >= 0){
+						_cp.value = ts(inParens+1, x);
+					}
+					inPseudo = inParens = -1;
+				}
+			}else if(cc == "#"){
+				// start of an ID match
+				endAll();
+				inId = x+1;
+			}else if(cc == "."){
+				// start of a class match
+				endAll();
+				inClass = x;
+			}else if(cc == ":"){
+				// start of a pseudo-selector match
+				endAll();
+				inPseudo = x;
+			}else if(cc == "["){
+				// start of an attribute match.
+				endAll();
+				inBrackets = x;
+				// provide a new structure for the attribute match to fill-in
+				_cp = {
+					/*=====
+					attr: null, type: null, matchFor: null
+					=====*/
+				};
+			}else if(cc == "("){
+				// we really only care if we've entered a parenthetical
+				// expression if we're already inside a pseudo-selector match
+				if(inPseudo >= 0){
+					// provide a new structure for the pseudo match to fill-in
+					_cp = {
+						name: ts(inPseudo+1, x),
+						value: null
+					};
+					currentPart.pseudos.push(_cp);
+				}
+				inParens = x;
+			}else if(
+				(cc == " ") &&
+				// if it's a space char and the last char is too, consume the
+				// current one without doing more work
+				(lc != cc)
+			){
+				endPart();
+			}
+		}
+		return queryParts;
+	};
+
+
+	////////////////////////////////////////////////////////////////////////
+	// DOM query infrastructure
+	////////////////////////////////////////////////////////////////////////
+
+	var agree = function(first, second){
+		// the basic building block of the yes/no chaining system. agree(f1,
+		// f2) generates a new function which returns the boolean results of
+		// both of the passed functions to a single logical-anded result. If
+		// either are not passed, the other is used exclusively.
+		if(!first){ return second; }
+		if(!second){ return first; }
+
+		return function(){
+			return first.apply(window, arguments) && second.apply(window, arguments);
+		}
+	};
+
+	var getArr = function(i, arr){
+		// helps us avoid array alloc when we don't need it
+		var r = arr||[]; // FIXME: should this be 'new d._NodeListCtor()' ?
+		if(i){ r.push(i); }
+		return r;
+	};
+
+	var _isElement = function(n){ return (1 == n.nodeType); };
+
+	// FIXME: need to coalesce _getAttr with defaultGetter
+	var blank = "";
+	var _getAttr = function(elem, attr){
+		if(!elem){ return blank; }
+		if(attr == "class"){
+			return elem.className || blank;
+		}
+		if(attr == "for"){
+			return elem.htmlFor || blank;
+		}
+		if(attr == "style"){
+			return elem.style.cssText || blank;
+		}
+		return (caseSensitive ? elem.getAttribute(attr) : elem.getAttribute(attr, 2)) || blank;
+	};
+
+	var attrs = {
+		"*=": function(attr, value){
+			return function(elem){
+				// E[foo*="bar"]
+				//		an E element whose "foo" attribute value contains
+				//		the substring "bar"
+				return (_getAttr(elem, attr).indexOf(value)>=0);
+			}
+		},
+		"^=": function(attr, value){
+			// E[foo^="bar"]
+			//		an E element whose "foo" attribute value begins exactly
+			//		with the string "bar"
+			return function(elem){
+				return (_getAttr(elem, attr).indexOf(value)==0);
+			}
+		},
+		"$=": function(attr, value){
+			// E[foo$="bar"]
+			//		an E element whose "foo" attribute value ends exactly
+			//		with the string "bar"
+			return function(elem){
+				var ea = " "+_getAttr(elem, attr);
+				return (ea.lastIndexOf(value)==(ea.length-value.length));
+			}
+		},
+		"~=": function(attr, value){
+			// E[foo~="bar"]
+			//		an E element whose "foo" attribute value is a list of
+			//		space-separated values, one of which is exactly equal
+			//		to "bar"
+
+			// return "[contains(concat(' ',@"+attr+",' '), ' "+ value +" ')]";
+			var tval = " "+value+" ";
+			return function(elem){
+				var ea = " "+_getAttr(elem, attr)+" ";
+				return (ea.indexOf(tval)>=0);
+			}
+		},
+		"|=": function(attr, value){
+			// E[hreflang|="en"]
+			//		an E element whose "hreflang" attribute has a
+			//		hyphen-separated list of values beginning (from the
+			//		left) with "en"
+			var valueDash = value+"-";
+			return function(elem){
+				var ea = _getAttr(elem, attr);
+				return (
+					(ea == value) ||
+					(ea.indexOf(valueDash)==0)
+				);
+			}
+		},
+		"=": function(attr, value){
+			return function(elem){
+				return (_getAttr(elem, attr) == value);
+			}
+		}
+	};
+
+	// avoid testing for node type if we can. Defining this in the negative
+	// here to avoid negation in the fast path.
+	var _noNES = (typeof getDoc().firstChild.nextElementSibling == "undefined");
+	var _ns = !_noNES ? "nextElementSibling" : "nextSibling";
+	var _ps = !_noNES ? "previousElementSibling" : "previousSibling";
+	var _simpleNodeTest = (_noNES ? _isElement : yesman);
+
+	var _lookLeft = function(node){
+		// look left
+		while(node = node[_ps]){
+			if(_simpleNodeTest(node)){ return false; }
+		}
+		return true;
+	};
+
+	var _lookRight = function(node){
+		// look right
+		while(node = node[_ns]){
+			if(_simpleNodeTest(node)){ return false; }
+		}
+		return true;
+	};
+
+	var getNodeIndex = function(node){
+		var root = node.parentNode;
+		var i = 0,
+			tret = root.children || root.childNodes,
+			ci = (node["_i"]||-1),
+			cl = (root["_l"]||-1);
+
+		if(!tret){ return -1; }
+		var l = tret.length;
+
+		// we calculate the parent length as a cheap way to invalidate the
+		// cache. It's not 100% accurate, but it's much more honest than what
+		// other libraries do
+		if( cl == l && ci >= 0 && cl >= 0 ){
+			// if it's legit, tag and release
+			return ci;
+		}
+
+		// else re-key things
+		root["_l"] = l;
+		ci = -1;
+		for(var te = root["firstElementChild"]||root["firstChild"]; te; te = te[_ns]){
+			if(_simpleNodeTest(te)){
+				te["_i"] = ++i;
+				if(node === te){
+					// NOTE:
+					//	shortcutting the return at this step in indexing works
+					//	very well for benchmarking but we avoid it here since
+					//	it leads to potential O(n^2) behavior in sequential
+					//	getNodexIndex operations on a previously un-indexed
+					//	parent. We may revisit this at a later time, but for
+					//	now we just want to get the right answer more often
+					//	than not.
+					ci = i;
+				}
+			}
+		}
+		return ci;
+	};
+
+	var isEven = function(elem){
+		return !((getNodeIndex(elem)) % 2);
+	};
+
+	var isOdd = function(elem){
+		return ((getNodeIndex(elem)) % 2);
+	};
+
+	var pseudos = {
+		"checked": function(name, condition){
+			return function(elem){
+				return !!("checked" in elem ? elem.checked : elem.selected);
+			}
+		},
+		"first-child": function(){ return _lookLeft; },
+		"last-child": function(){ return _lookRight; },
+		"only-child": function(name, condition){
+			return function(node){
+				return _lookLeft(node) && _lookRight(node);
+			};
+		},
+		"empty": function(name, condition){
+			return function(elem){
+				// DomQuery and jQuery get this wrong, oddly enough.
+				// The CSS 3 selectors spec is pretty explicit about it, too.
+				var cn = elem.childNodes;
+				var cnl = elem.childNodes.length;
+				// if(!cnl){ return true; }
+				for(var x=cnl-1; x >= 0; x--){
+					var nt = cn[x].nodeType;
+					if((nt === 1)||(nt == 3)){ return false; }
+				}
+				return true;
+			}
+		},
+		"contains": function(name, condition){
+			var cz = condition.charAt(0);
+			if( cz == '"' || cz == "'" ){ //remove quote
+				condition = condition.slice(1, -1);
+			}
+			return function(elem){
+				return (elem.innerHTML.indexOf(condition) >= 0);
+			}
+		},
+		"not": function(name, condition){
+			var p = getQueryParts(condition)[0];
+			var ignores = { el: 1 };
+			if(p.tag != "*"){
+				ignores.tag = 1;
+			}
+			if(!p.classes.length){
+				ignores.classes = 1;
+			}
+			var ntf = getSimpleFilterFunc(p, ignores);
+			return function(elem){
+				return (!ntf(elem));
+			}
+		},
+		"nth-child": function(name, condition){
+			var pi = parseInt;
+			// avoid re-defining function objects if we can
+			if(condition == "odd"){
+				return isOdd;
+			}else if(condition == "even"){
+				return isEven;
+			}
+			// FIXME: can we shorten this?
+			if(condition.indexOf("n") != -1){
+				var tparts = condition.split("n", 2);
+				var pred = tparts[0] ? ((tparts[0] == '-') ? -1 : pi(tparts[0])) : 1;
+				var idx = tparts[1] ? pi(tparts[1]) : 0;
+				var lb = 0, ub = -1;
+				if(pred > 0){
+					if(idx < 0){
+						idx = (idx % pred) && (pred + (idx % pred));
+					}else if(idx>0){
+						if(idx >= pred){
+							lb = idx - idx % pred;
+						}
+						idx = idx % pred;
+					}
+				}else if(pred<0){
+					pred *= -1;
+					// idx has to be greater than 0 when pred is negative;
+					// shall we throw an error here?
+					if(idx > 0){
+						ub = idx;
+						idx = idx % pred;
+					}
+				}
+				if(pred > 0){
+					return function(elem){
+						var i = getNodeIndex(elem);
+						return (i>=lb) && (ub<0 || i<=ub) && ((i % pred) == idx);
+					}
+				}else{
+					condition = idx;
+				}
+			}
+			var ncount = pi(condition);
+			return function(elem){
+				return (getNodeIndex(elem) == ncount);
+			}
+		}
+	};
+
+	var defaultGetter = (dojo.isIE && (dojo.isIE < 9 || dojo.isQuirks)) ? function(cond){
+		var clc = cond.toLowerCase();
+		if(clc == "class"){ cond = "className"; }
+		return function(elem){
+			return (caseSensitive ? elem.getAttribute(cond) : elem[cond]||elem[clc]);
+		}
+	} : function(cond){
+		return function(elem){
+			return (elem && elem.getAttribute && elem.hasAttribute(cond));
+		}
+	};
+
+	var getSimpleFilterFunc = function(query, ignores){
+		// generates a node tester function based on the passed query part. The
+		// query part is one of the structures generated by the query parser
+		// when it creates the query AST. The "ignores" object specifies which
+		// (if any) tests to skip, allowing the system to avoid duplicating
+		// work where it may have already been taken into account by other
+		// factors such as how the nodes to test were fetched in the first
+		// place
+		if(!query){ return yesman; }
+		ignores = ignores||{};
+
+		var ff = null;
+
+		if(!("el" in ignores)){
+			ff = agree(ff, _isElement);
+		}
+
+		if(!("tag" in ignores)){
+			if(query.tag != "*"){
+				ff = agree(ff, function(elem){
+					return (elem && (elem.tagName == query.getTag()));
+				});
+			}
+		}
+
+		if(!("classes" in ignores)){
+			each(query.classes, function(cname, idx, arr){
+				// get the class name
+				/*
+				var isWildcard = cname.charAt(cname.length-1) == "*";
+				if(isWildcard){
+					cname = cname.substr(0, cname.length-1);
+				}
+				// I dislike the regex thing, even if memoized in a cache, but it's VERY short
+				var re = new RegExp("(?:^|\\s)" + cname + (isWildcard ? ".*" : "") + "(?:\\s|$)");
+				*/
+				var re = new RegExp("(?:^|\\s)" + cname + "(?:\\s|$)");
+				ff = agree(ff, function(elem){
+					return re.test(elem.className);
+				});
+				ff.count = idx;
+			});
+		}
+
+		if(!("pseudos" in ignores)){
+			each(query.pseudos, function(pseudo){
+				var pn = pseudo.name;
+				if(pseudos[pn]){
+					ff = agree(ff, pseudos[pn](pn, pseudo.value));
+				}
+			});
+		}
+
+		if(!("attrs" in ignores)){
+			each(query.attrs, function(attr){
+				var matcher;
+				var a = attr.attr;
+				// type, attr, matchFor
+				if(attr.type && attrs[attr.type]){
+					matcher = attrs[attr.type](a, attr.matchFor);
+				}else if(a.length){
+					matcher = defaultGetter(a);
+				}
+				if(matcher){
+					ff = agree(ff, matcher);
+				}
+			});
+		}
+
+		if(!("id" in ignores)){
+			if(query.id){
+				ff = agree(ff, function(elem){
+					return (!!elem && (elem.id == query.id));
+				});
+			}
+		}
+
+		if(!ff){
+			if(!("default" in ignores)){
+				ff = yesman;
+			}
+		}
+		return ff;
+	};
+
+	var _nextSibling = function(filterFunc){
+		return function(node, ret, bag){
+			while(node = node[_ns]){
+				if(_noNES && (!_isElement(node))){ continue; }
+				if(
+					(!bag || _isUnique(node, bag)) &&
+					filterFunc(node)
+				){
+					ret.push(node);
+				}
+				break;
+			}
+			return ret;
+		}
+	};
+
+	var _nextSiblings = function(filterFunc){
+		return function(root, ret, bag){
+			var te = root[_ns];
+			while(te){
+				if(_simpleNodeTest(te)){
+					if(bag && !_isUnique(te, bag)){
+						break;
+					}
+					if(filterFunc(te)){
+						ret.push(te);
+					}
+				}
+				te = te[_ns];
+			}
+			return ret;
+		}
+	};
+
+	// get an array of child *elements*, skipping text and comment nodes
+	var _childElements = function(filterFunc){
+		filterFunc = filterFunc||yesman;
+		return function(root, ret, bag){
+			// get an array of child elements, skipping text and comment nodes
+			var te, x = 0, tret = root.children || root.childNodes;
+			while(te = tret[x++]){
+				if(
+					_simpleNodeTest(te) &&
+					(!bag || _isUnique(te, bag)) &&
+					(filterFunc(te, x))
+				){
+					ret.push(te);
+				}
+			}
+			return ret;
+		};
+	};
+
+	/*
+	// thanks, Dean!
+	var itemIsAfterRoot = d.isIE ? function(item, root){
+		return (item.sourceIndex > root.sourceIndex);
+	} : function(item, root){
+		return (item.compareDocumentPosition(root) == 2);
+	};
+	*/
+
+	// test to see if node is below root
+	var _isDescendant = function(node, root){
+		var pn = node.parentNode;
+		while(pn){
+			if(pn == root){
+				break;
+			}
+			pn = pn.parentNode;
+		}
+		return !!pn;
+	};
+
+	var _getElementsFuncCache = {};
+
+	var getElementsFunc = function(query){
+		var retFunc = _getElementsFuncCache[query.query];
+		// if we've got a cached dispatcher, just use that
+		if(retFunc){ return retFunc; }
+		// else, generate a new on
+
+		// NOTE:
+		//		this function returns a function that searches for nodes and
+		//		filters them.  The search may be specialized by infix operators
+		//		(">", "~", or "+") else it will default to searching all
+		//		descendants (the " " selector). Once a group of children is
+		//		found, a test function is applied to weed out the ones we
+		//		don't want. Many common cases can be fast-pathed. We spend a
+		//		lot of cycles to create a dispatcher that doesn't do more work
+		//		than necessary at any point since, unlike this function, the
+		//		dispatchers will be called every time. The logic of generating
+		//		efficient dispatchers looks like this in pseudo code:
+		//
+		//		# if it's a purely descendant query (no ">", "+", or "~" modifiers)
+		//		if infixOperator == " ":
+		//			if only(id):
+		//				return def(root):
+		//					return d.byId(id, root);
+		//
+		//			elif id:
+		//				return def(root):
+		//					return filter(d.byId(id, root));
+		//
+		//			elif cssClass && getElementsByClassName:
+		//				return def(root):
+		//					return filter(root.getElementsByClassName(cssClass));
+		//
+		//			elif only(tag):
+		//				return def(root):
+		//					return root.getElementsByTagName(tagName);
+		//
+		//			else:
+		//				# search by tag name, then filter
+		//				return def(root):
+		//					return filter(root.getElementsByTagName(tagName||"*"));
+		//
+		//		elif infixOperator == ">":
+		//			# search direct children
+		//			return def(root):
+		//				return filter(root.children);
+		//
+		//		elif infixOperator == "+":
+		//			# search next sibling
+		//			return def(root):
+		//				return filter(root.nextElementSibling);
+		//
+		//		elif infixOperator == "~":
+		//			# search rightward siblings
+		//			return def(root):
+		//				return filter(nextSiblings(root));
+
+		var io = query.infixOper;
+		var oper = (io ? io.oper : "");
+		// the default filter func which tests for all conditions in the query
+		// part. This is potentially inefficient, so some optimized paths may
+		// re-define it to test fewer things.
+		var filterFunc = getSimpleFilterFunc(query, { el: 1 });
+		var qt = query.tag;
+		var wildcardTag = ("*" == qt);
+		var ecs = getDoc()["getElementsByClassName"];
+
+		if(!oper){
+			// if there's no infix operator, then it's a descendant query. ID
+			// and "elements by class name" variants can be accelerated so we
+			// call them out explicitly:
+			if(query.id){
+				// testing shows that the overhead of yesman() is acceptable
+				// and can save us some bytes vs. re-defining the function
+				// everywhere.
+				filterFunc = (!query.loops && wildcardTag) ?
+					yesman :
+					getSimpleFilterFunc(query, { el: 1, id: 1 });
+
+				retFunc = function(root, arr){
+					var te = dom.byId(query.id, (root.ownerDocument||root));
+					if(!te || !filterFunc(te)){ return; }
+					if(9 == root.nodeType){ // if root's a doc, we just return directly
+						return getArr(te, arr);
+					}else{ // otherwise check ancestry
+						if(_isDescendant(te, root)){
+							return getArr(te, arr);
+						}
+					}
+				}
+			}else if(
+				ecs &&
+				// isAlien check. Workaround for Prototype.js being totally evil/dumb.
+				/\{\s*\[native code\]\s*\}/.test(String(ecs)) &&
+				query.classes.length &&
+				!cssCaseBug
+			){
+				// it's a class-based query and we've got a fast way to run it.
+
+				// ignore class and ID filters since we will have handled both
+				filterFunc = getSimpleFilterFunc(query, { el: 1, classes: 1, id: 1 });
+				var classesString = query.classes.join(" ");
+				retFunc = function(root, arr, bag){
+					var ret = getArr(0, arr), te, x=0;
+					var tret = root.getElementsByClassName(classesString);
+					while((te = tret[x++])){
+						if(filterFunc(te, root) && _isUnique(te, bag)){
+							ret.push(te);
+						}
+					}
+					return ret;
+				};
+
+			}else if(!wildcardTag && !query.loops){
+				// it's tag only. Fast-path it.
+				retFunc = function(root, arr, bag){
+					var ret = getArr(0, arr), te, x=0;
+					var tret = root.getElementsByTagName(query.getTag());
+					while((te = tret[x++])){
+						if(_isUnique(te, bag)){
+							ret.push(te);
+						}
+					}
+					return ret;
+				};
+			}else{
+				// the common case:
+				//		a descendant selector without a fast path. By now it's got
+				//		to have a tag selector, even if it's just "*" so we query
+				//		by that and filter
+				filterFunc = getSimpleFilterFunc(query, { el: 1, tag: 1, id: 1 });
+				retFunc = function(root, arr, bag){
+					var ret = getArr(0, arr), te, x=0;
+					// we use getTag() to avoid case sensitivity issues
+					var tret = root.getElementsByTagName(query.getTag());
+					while((te = tret[x++])){
+						if(filterFunc(te, root) && _isUnique(te, bag)){
+							ret.push(te);
+						}
+					}
+					return ret;
+				};
+			}
+		}else{
+			// the query is scoped in some way. Instead of querying by tag we
+			// use some other collection to find candidate nodes
+			var skipFilters = { el: 1 };
+			if(wildcardTag){
+				skipFilters.tag = 1;
+			}
+			filterFunc = getSimpleFilterFunc(query, skipFilters);
+			if("+" == oper){
+				retFunc = _nextSibling(filterFunc);
+			}else if("~" == oper){
+				retFunc = _nextSiblings(filterFunc);
+			}else if(">" == oper){
+				retFunc = _childElements(filterFunc);
+			}
+		}
+		// cache it and return
+		return _getElementsFuncCache[query.query] = retFunc;
+	};
+
+	var filterDown = function(root, queryParts){
+		// NOTE:
+		//		this is the guts of the DOM query system. It takes a list of
+		//		parsed query parts and a root and finds children which match
+		//		the selector represented by the parts
+		var candidates = getArr(root), qp, x, te, qpl = queryParts.length, bag, ret;
+
+		for(var i = 0; i < qpl; i++){
+			ret = [];
+			qp = queryParts[i];
+			x = candidates.length - 1;
+			if(x > 0){
+				// if we have more than one root at this level, provide a new
+				// hash to use for checking group membership but tell the
+				// system not to post-filter us since we will already have been
+				// gauranteed to be unique
+				bag = {};
+				ret.nozip = true;
+			}
+			var gef = getElementsFunc(qp);
+			for(var j = 0; (te = candidates[j]); j++){
+				// for every root, get the elements that match the descendant
+				// selector, adding them to the "ret" array and filtering them
+				// via membership in this level's bag. If there are more query
+				// parts, then this level's return will be used as the next
+				// level's candidates
+				gef(te, ret, bag);
+			}
+			if(!ret.length){ break; }
+			candidates = ret;
+		}
+		return ret;
+	};
+
+	////////////////////////////////////////////////////////////////////////
+	// the query runner
+	////////////////////////////////////////////////////////////////////////
+
+	// these are the primary caches for full-query results. The query
+	// dispatcher functions are generated then stored here for hash lookup in
+	// the future
+	var _queryFuncCacheDOM = {},
+		_queryFuncCacheQSA = {};
+
+	// this is the second level of spliting, from full-length queries (e.g.,
+	// "div.foo .bar") into simple query expressions (e.g., ["div.foo",
+	// ".bar"])
+	var getStepQueryFunc = function(query){
+		var qparts = getQueryParts(trim(query));
+
+		// if it's trivial, avoid iteration and zipping costs
+		if(qparts.length == 1){
+			// we optimize this case here to prevent dispatch further down the
+			// chain, potentially slowing things down. We could more elegantly
+			// handle this in filterDown(), but it's slower for simple things
+			// that need to be fast (e.g., "#someId").
+			var tef = getElementsFunc(qparts[0]);
+			return function(root){
+				var r = tef(root, []);
+				if(r){ r.nozip = true; }
+				return r;
+			}
+		}
+
+		// otherwise, break it up and return a runner that iterates over the parts recursively
+		return function(root){
+			return filterDown(root, qparts);
+		}
+	};
+
+	// NOTES:
+	//	* we can't trust QSA for anything but document-rooted queries, so
+	//	  caching is split into DOM query evaluators and QSA query evaluators
+	//	* caching query results is dirty and leak-prone (or, at a minimum,
+	//	  prone to unbounded growth). Other toolkits may go this route, but
+	//	  they totally destroy their own ability to manage their memory
+	//	  footprint. If we implement it, it should only ever be with a fixed
+	//	  total element reference # limit and an LRU-style algorithm since JS
+	//	  has no weakref support. Caching compiled query evaluators is also
+	//	  potentially problematic, but even on large documents the size of the
+	//	  query evaluators is often < 100 function objects per evaluator (and
+	//	  LRU can be applied if it's ever shown to be an issue).
+	//	* since IE's QSA support is currently only for HTML documents and even
+	//	  then only in IE 8's "standards mode", we have to detect our dispatch
+	//	  route at query time and keep 2 separate caches. Ugg.
+
+	// we need to determine if we think we can run a given query via
+	// querySelectorAll or if we'll need to fall back on DOM queries to get
+	// there. We need a lot of information about the environment and the query
+	// to make the determiniation (e.g. does it support QSA, does the query in
+	// question work in the native QSA impl, etc.).
+	var nua = navigator.userAgent;
+	// some versions of Safari provided QSA, but it was buggy and crash-prone.
+	// We need te detect the right "internal" webkit version to make this work.
+	var wk = "WebKit/";
+	var is525 = (
+		dojo.isWebKit &&
+		(nua.indexOf(wk) > 0) &&
+		(parseFloat(nua.split(wk)[1]) > 528)
+	);
+
+	// IE QSA queries may incorrectly include comment nodes, so we throw the
+	// zipping function into "remove" comments mode instead of the normal "skip
+	// it" which every other QSA-clued browser enjoys
+	var noZip = dojo.isIE ? "commentStrip" : "nozip";
+
+	var qsa = "querySelectorAll";
+	var qsaAvail = (
+		!!getDoc()[qsa] &&
+		// see #5832
+		(!dojo.isSafari || (dojo.isSafari > 3.1) || is525 )
+	);
+
+	//Don't bother with n+3 type of matches, IE complains if we modify those.
+	var infixSpaceRe = /n\+\d|([^ ])?([>~+])([^ =])?/g;
+	var infixSpaceFunc = function(match, pre, ch, post){
+		return ch ? (pre ? pre + " " : "") + ch + (post ? " " + post : "") : /*n+3*/ match;
+	};
+
+	var getQueryFunc = function(query, forceDOM){
+		//Normalize query. The CSS3 selectors spec allows for omitting spaces around
+		//infix operators, >, ~ and +
+		//Do the work here since detection for spaces is used as a simple "not use QSA"
+		//test below.
+		query = query.replace(infixSpaceRe, infixSpaceFunc);
+
+		if(qsaAvail){
+			// if we've got a cached variant and we think we can do it, run it!
+			var qsaCached = _queryFuncCacheQSA[query];
+			if(qsaCached && !forceDOM){ return qsaCached; }
+		}
+
+		// else if we've got a DOM cached variant, assume that we already know
+		// all we need to and use it
+		var domCached = _queryFuncCacheDOM[query];
+		if(domCached){ return domCached; }
+
+		// TODO:
+		//		today we're caching DOM and QSA branches separately so we
+		//		recalc useQSA every time. If we had a way to tag root+query
+		//		efficiently, we'd be in good shape to do a global cache.
+
+		var qcz = query.charAt(0);
+		var nospace = (-1 == query.indexOf(" "));
+
+		// byId searches are wicked fast compared to QSA, even when filtering
+		// is required
+		if( (query.indexOf("#") >= 0) && (nospace) ){
+			forceDOM = true;
+		}
+
+		var useQSA = (
+			qsaAvail && (!forceDOM) &&
+			// as per CSS 3, we can't currently start w/ combinator:
+			//		http://www.w3.org/TR/css3-selectors/#w3cselgrammar
+			(specials.indexOf(qcz) == -1) &&
+			// IE's QSA impl sucks on pseudos
+			(!dojo.isIE || (query.indexOf(":") == -1)) &&
+
+			(!(cssCaseBug && (query.indexOf(".") >= 0))) &&
+
+			// FIXME:
+			//		need to tighten up browser rules on ":contains" and "|=" to
+			//		figure out which aren't good
+			//		Latest webkit (around 531.21.8) does not seem to do well with :checked on option
+			//		elements, even though according to spec, selected options should
+			//		match :checked. So go nonQSA for it:
+			//		http://bugs.dojotoolkit.org/ticket/5179
+			(query.indexOf(":contains") == -1) && (query.indexOf(":checked") == -1) &&
+			(query.indexOf("|=") == -1) // some browsers don't grok it
+		);
+
+		// TODO:
+		//		if we've got a descendant query (e.g., "> .thinger" instead of
+		//		just ".thinger") in a QSA-able doc, but are passed a child as a
+		//		root, it should be possible to give the item a synthetic ID and
+		//		trivially rewrite the query to the form "#synid > .thinger" to
+		//		use the QSA branch
+
+
+		if(useQSA){
+			var tq = (specials.indexOf(query.charAt(query.length-1)) >= 0) ?
+						(query + " *") : query;
+			return _queryFuncCacheQSA[query] = function(root){
+				try{
+					// the QSA system contains an egregious spec bug which
+					// limits us, effectively, to only running QSA queries over
+					// entire documents.  See:
+					//		http://ejohn.org/blog/thoughts-on-queryselectorall/
+					//	despite this, we can also handle QSA runs on simple
+					//	selectors, but we don't want detection to be expensive
+					//	so we're just checking for the presence of a space char
+					//	right now. Not elegant, but it's cheaper than running
+					//	the query parser when we might not need to
+					if(!((9 == root.nodeType) || nospace)){ throw ""; }
+					var r = root[qsa](tq);
+					// skip expensive duplication checks and just wrap in a NodeList
+					r[noZip] = true;
+					return r;
+				}catch(e){
+					// else run the DOM branch on this query, ensuring that we
+					// default that way in the future
+					return getQueryFunc(query, true)(root);
+				}
+			}
+		}else{
+			// DOM branch
+			var parts = query.split(/\s*,\s*/);
+			return _queryFuncCacheDOM[query] = ((parts.length < 2) ?
+				// if not a compound query (e.g., ".foo, .bar"), cache and return a dispatcher
+				getStepQueryFunc(query) :
+				// if it *is* a complex query, break it up into its
+				// constituent parts and return a dispatcher that will
+				// merge the parts when run
+				function(root){
+					var pindex = 0, // avoid array alloc for every invocation
+						ret = [],
+						tp;
+					while((tp = parts[pindex++])){
+						ret = ret.concat(getStepQueryFunc(tp)(root));
+					}
+					return ret;
+				}
+			);
+		}
+	};
+
+	var _zipIdx = 0;
+
+	// NOTE:
+	//		this function is Moo inspired, but our own impl to deal correctly
+	//		with XML in IE
+	var _nodeUID = dojo.isIE ? function(node){
+		if(caseSensitive){
+			// XML docs don't have uniqueID on their nodes
+			return (node.getAttribute("_uid") || node.setAttribute("_uid", ++_zipIdx) || _zipIdx);
+
+		}else{
+			return node.uniqueID;
+		}
+	} :
+	function(node){
+		return (node._uid || (node._uid = ++_zipIdx));
+	};
+
+	// determine if a node in is unique in a "bag". In this case we don't want
+	// to flatten a list of unique items, but rather just tell if the item in
+	// question is already in the bag. Normally we'd just use hash lookup to do
+	// this for us but IE's DOM is busted so we can't really count on that. On
+	// the upside, it gives us a built in unique ID function.
+	var _isUnique = function(node, bag){
+		if(!bag){ return 1; }
+		var id = _nodeUID(node);
+		if(!bag[id]){ return bag[id] = 1; }
+		return 0;
+	};
+
+	// attempt to efficiently determine if an item in a list is a dupe,
+	// returning a list of "uniques", hopefully in doucment order
+	var _zipIdxName = "_zipIdx";
+	var _zip = function(arr){
+		if(arr && arr.nozip){
+			return arr;
+		}
+		var ret = [];
+		if(!arr || !arr.length){ return ret; }
+		if(arr[0]){
+			ret.push(arr[0]);
+		}
+		if(arr.length < 2){ return ret; }
+
+		_zipIdx++;
+
+		// we have to fork here for IE and XML docs because we can't set
+		// expandos on their nodes (apparently). *sigh*
+		if(dojo.isIE && caseSensitive){
+			var szidx = _zipIdx+"";
+			arr[0].setAttribute(_zipIdxName, szidx);
+			for(var x = 1, te; te = arr[x]; x++){
+				if(arr[x].getAttribute(_zipIdxName) != szidx){
+					ret.push(te);
+				}
+				te.setAttribute(_zipIdxName, szidx);
+			}
+		}else if(dojo.isIE && arr.commentStrip){
+			try{
+				for(var x = 1, te; te = arr[x]; x++){
+					if(_isElement(te)){
+						ret.push(te);
+					}
+				}
+			}catch(e){ /* squelch */ }
+		}else{
+			if(arr[0]){ arr[0][_zipIdxName] = _zipIdx; }
+			for(var x = 1, te; te = arr[x]; x++){
+				if(arr[x][_zipIdxName] != _zipIdx){
+					ret.push(te);
+				}
+				te[_zipIdxName] = _zipIdx;
+			}
+		}
+		return ret;
+	};
+
+	// the main executor
+	var query = function(/*String*/ query, /*String|DOMNode?*/ root){
+		//	summary:
+		//		Returns nodes which match the given CSS3 selector, searching the
+		//		entire document by default but optionally taking a node to scope
+		//		the search by. Returns an array.
+		//	description:
+		//		dojo.query() is the swiss army knife of DOM node manipulation in
+		//		Dojo. Much like Prototype's "$$" (bling-bling) function or JQuery's
+		//		"$" function, dojo.query provides robust, high-performance
+		//		CSS-based node selector support with the option of scoping searches
+		//		to a particular sub-tree of a document.
+		//
+		//		Supported Selectors:
+		//		--------------------
+		//
+		//		acme supports a rich set of CSS3 selectors, including:
+		//
+		//			* class selectors (e.g., `.foo`)
+		//			* node type selectors like `span`
+		//			* ` ` descendant selectors
+		//			* `>` child element selectors
+		//			* `#foo` style ID selectors
+		//			* `*` universal selector
+		//			* `~`, the preceded-by sibling selector
+		//			* `+`, the immediately preceded-by sibling selector
+		//			* attribute queries:
+		//			|	* `[foo]` attribute presence selector
+		//			|	* `[foo='bar']` attribute value exact match
+		//			|	* `[foo~='bar']` attribute value list item match
+		//			|	* `[foo^='bar']` attribute start match
+		//			|	* `[foo$='bar']` attribute end match
+		//			|	* `[foo*='bar']` attribute substring match
+		//			* `:first-child`, `:last-child`, and `:only-child` positional selectors
+		//			* `:empty` content emtpy selector
+		//			* `:checked` pseudo selector
+		//			* `:nth-child(n)`, `:nth-child(2n+1)` style positional calculations
+		//			* `:nth-child(even)`, `:nth-child(odd)` positional selectors
+		//			* `:not(...)` negation pseudo selectors
+		//
+		//		Any legal combination of these selectors will work with
+		//		`dojo.query()`, including compound selectors ("," delimited).
+		//		Very complex and useful searches can be constructed with this
+		//		palette of selectors and when combined with functions for
+		//		manipulation presented by dojo.NodeList, many types of DOM
+		//		manipulation operations become very straightforward.
+		//
+		//		Unsupported Selectors:
+		//		----------------------
+		//
+		//		While dojo.query handles many CSS3 selectors, some fall outside of
+		//		what's reasonable for a programmatic node querying engine to
+		//		handle. Currently unsupported selectors include:
+		//
+		//			* namespace-differentiated selectors of any form
+		//			* all `::` pseduo-element selectors
+		//			* certain pseduo-selectors which don't get a lot of day-to-day use:
+		//			|	* `:root`, `:lang()`, `:target`, `:focus`
+		//			* all visual and state selectors:
+		//			|	* `:root`, `:active`, `:hover`, `:visisted`, `:link`,
+		//				  `:enabled`, `:disabled`
+		//			* `:*-of-type` pseudo selectors
+		//
+		//		dojo.query and XML Documents:
+		//		-----------------------------
+		//
+		//		`dojo.query` (as of dojo 1.2) supports searching XML documents
+		//		in a case-sensitive manner. If an HTML document is served with
+		//		a doctype that forces case-sensitivity (e.g., XHTML 1.1
+		//		Strict), dojo.query() will detect this and "do the right
+		//		thing". Case sensitivity is dependent upon the document being
+		//		searched and not the query used. It is therefore possible to
+		//		use case-sensitive queries on strict sub-documents (iframes,
+		//		etc.) or XML documents while still assuming case-insensitivity
+		//		for a host/root document.
+		//
+		//		Non-selector Queries:
+		//		---------------------
+		//
+		//		If something other than a String is passed for the query,
+		//		`dojo.query` will return a new `dojo.NodeList` instance
+		//		constructed from that parameter alone and all further
+		//		processing will stop. This means that if you have a reference
+		//		to a node or NodeList, you can quickly construct a new NodeList
+		//		from the original by calling `dojo.query(node)` or
+		//		`dojo.query(list)`.
+		//
+		//	query:
+		//		The CSS3 expression to match against. For details on the syntax of
+		//		CSS3 selectors, see <http://www.w3.org/TR/css3-selectors/#selectors>
+		//	root:
+		//		A DOMNode (or node id) to scope the search from. Optional.
+		//	returns: Array
+		//	example:
+		//		search the entire document for elements with the class "foo":
+		//	|	dojo.query(".foo");
+		//		these elements will match:
+		//	|	<span class="foo"></span>
+		//	|	<span class="foo bar"></span>
+		//	|	<p class="thud foo"></p>
+		//	example:
+		//		search the entire document for elements with the classes "foo" *and* "bar":
+		//	|	dojo.query(".foo.bar");
+		//		these elements will match:
+		//	|	<span class="foo bar"></span>
+		//		while these will not:
+		//	|	<span class="foo"></span>
+		//	|	<p class="thud foo"></p>
+		//	example:
+		//		find `<span>` elements which are descendants of paragraphs and
+		//		which have a "highlighted" class:
+		//	|	dojo.query("p span.highlighted");
+		//		the innermost span in this fragment matches:
+		//	|	<p class="foo">
+		//	|		<span>...
+		//	|			<span class="highlighted foo bar">...</span>
+		//	|		</span>
+		//	|	</p>
+		//	example:
+		//		set an "odd" class on all odd table rows inside of the table
+		//		`#tabular_data`, using the `>` (direct child) selector to avoid
+		//		affecting any nested tables:
+		//	|	dojo.query("#tabular_data > tbody > tr:nth-child(odd)").addClass("odd");
+		//	example:
+		//		remove all elements with the class "error" from the document
+		//		and store them in a list:
+		//	|	var errors = dojo.query(".error").orphan();
+		//	example:
+		//		add an onclick handler to every submit button in the document
+		//		which causes the form to be sent via Ajax instead:
+		//	|	dojo.query("input[type='submit']").onclick(function(e){
+		//	|		dojo.stopEvent(e); // prevent sending the form
+		//	|		var btn = e.target;
+		//	|		dojo.xhrPost({
+		//	|			form: btn.form,
+		//	|			load: function(data){
+		//	|				// replace the form with the response
+		//	|				var div = dojo.doc.createElement("div");
+		//	|				dojo.place(div, btn.form, "after");
+		//	|				div.innerHTML = data;
+		//	|				dojo.style(btn.form, "display", "none");
+		//	|			}
+		//	|		});
+		//	|	});
+
+		root = root||getDoc();
+		var od = root.ownerDocument||root.documentElement;
+
+		// throw the big case sensitivity switch
+
+		// NOTE:
+		//		Opera in XHTML mode doesn't detect case-sensitivity correctly
+		//		and it's not clear that there's any way to test for it
+		caseSensitive = (root.contentType && root.contentType=="application/xml") ||
+						(dojo.isOpera && (root.doctype || od.toString() == "[object XMLDocument]")) ||
+						(!!od) &&
+				(dojo.isIE ? od.xml : (root.xmlVersion || od.xmlVersion));
+
+		// NOTE:
+		//		adding "true" as the 2nd argument to getQueryFunc is useful for
+		//		testing the DOM branch without worrying about the
+		//		behavior/performance of the QSA branch.
+		var r = getQueryFunc(query)(root);
+
+		// FIXME:
+		//		need to investigate this branch WRT #8074 and #8075
+		if(r && r.nozip){
+			return r;
+		}
+		return _zip(r); // dojo.NodeList
+	};
+	query.filter = function(/*Node[]*/ nodeList, /*String*/ filter, /*String|DOMNode?*/ root){
+		// summary:
+		// 		function for filtering a NodeList based on a selector, optimized for simple selectors
+		var tmpNodeList = [],
+			parts = getQueryParts(filter),
+			filterFunc =
+				(parts.length == 1 && !/[^\w#\.]/.test(filter)) ?
+				getSimpleFilterFunc(parts[0]) :
+				function(node){
+					return dojo.query(filter, root).indexOf(node) != -1;
+				};
+		for(var x = 0, te; te = nodeList[x]; x++){
+			if(filterFunc(te)){ tmpNodeList.push(te); }
+		}
+		return tmpNodeList;
+	};
+	return query;
+});//end defineQuery
diff --git a/selector/lite.js b/selector/lite.js
index 550edf1..8228828 100644
--- a/selector/lite.js
+++ b/selector/lite.js
@@ -1,264 +1,264 @@
-define(["../has", "../_base/kernel"], function(has, dojo){
-"use strict";
-// summary:
-//		A small lightweight query selector engine that implements CSS2.1 selectors 
-// 		minus pseudo-classes and the sibling combinator, plus CSS3 attribute selectors
-var testDiv = document.createElement("div");
-var matchesSelector = testDiv.matchesSelector || testDiv.webkitMatchesSelector || testDiv.mozMatchesSelector || testDiv.msMatchesSelector || testDiv.oMatchesSelector; // IE9, WebKit, Firefox have this, but not Opera yet
-var querySelectorAll = testDiv.querySelectorAll;
-has.add("dom-matches-selector", !!matchesSelector);
-has.add("dom-qsa", !!querySelectorAll); 
-
-// this is a simple query engine. It has handles basic selectors, and for simple
-// common selectors is extremely fast
-var liteEngine = function(selector, root){
-	if(combine && selector.indexOf(',') > -1){
-		return combine(selector, root);
-	}
-	var match = (querySelectorAll ? 
-		/^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/ : // this one only matches on simple queries where we can beat qSA with specific methods
-		/^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/) // this one matches parts of the query that we can use to speed up manual filtering
-			.exec(selector);
-	root = root || document;
-	if(match){
-		// fast path regardless of whether or not querySelectorAll exists
-		if(match[2]){
-			// an #id
-			// use dojo.byId if available as it fixes the id retrieval in IE
-			var found = dojo.byId ? dojo.byId(match[2]) : document.getElementById(match[2]);
-			if(!found || (match[1] && match[1] != found.tagName.toLowerCase())){
-				// if there is a tag qualifer and it doesn't match, no matches
-				return [];
-			}
-			if(root != document){
-				// there is a root element, make sure we are a child of it
-				var parent = found;
-				while(parent != root){
-					parent = parent.parentNode;
-					if(!parent){
-						return [];
-					}
-				}
-			}
-			return match[3] ?
-					liteEngine(match[3], found) 
-					: [found];
-		}
-		if(match[3] && root.getElementsByClassName){
-			// a .class
-			return root.getElementsByClassName(match[4]);
-		}
-		var found;
-		if(match[5]){
-			// a tag
-			found = root.getElementsByTagName(match[5]);
-			if(match[4] || match[6]){
-				selector = (match[4] || "") + match[6];
-			}else{
-				// that was the entirety of the query, return results
-				return found;
-			}
-		}
-	}
-	if(querySelectorAll){
-		// qSA works strangely on Element-rooted queries
-		// We can work around this by specifying an extra ID on the root
-		// and working up from there (Thanks to Andrew Dupont for the technique)
-		// IE 8 doesn't work on object elements
-		if (root.nodeType === 1 && root.nodeName.toLowerCase() !== "object"){				
-			return useRoot(root, selector, root.querySelectorAll);
-		}else{
-			// we can use the native qSA
-			return root.querySelectorAll(selector);
-		}
-	}else if(!found){
-		// search all children and then filter
-		found = root.getElementsByTagName("*");
-	}
-	// now we filter the nodes that were found using the matchesSelector
-	var results = [];
-	for(var i = 0, l = found.length; i < l; i++){
-		var node = found[i];
-		if(node.nodeType == 1 && jsMatchesSelector(node, selector, root)){
-			// keep the nodes that match the selector
-			results.push(node);
-		}
-	}
-	return results;
-};
-var useRoot = function(context, query, method){
-	// this function creates a temporary id so we can do rooted qSA queries, this is taken from sizzle
-	var oldContext = context,
-		old = context.getAttribute( "id" ),
-		nid = old || "__dojo__",
-		hasParent = context.parentNode,
-		relativeHierarchySelector = /^\s*[+~]/.test( query );
-
-	if(relativeHierarchySelector && !hasParent){
-		return [];
-	}
-	if(!old){
-		context.setAttribute("id", nid);
-	}else{
-		nid = nid.replace(/'/g, "\\$&");
-	}
-	if(relativeHierarchySelector && hasParent){
-		context = context.parentNode;
-	}
-
-	try {
-		return method.call(context, "[id='" + nid + "'] " + query );
-	} finally {
-		if ( !old ) {
-			oldContext.removeAttribute( "id" );
-		}
-	}
-};
-
-if(!has("dom-matches-selector")){
-	var jsMatchesSelector = (function(){
-		// a JS implementation of CSS selector matching, first we start with the various handlers
-		var caseFix = testDiv.tagName == "div" ? "toLowerCase" : "toUpperCase";
-		function tag(tagName){
-			tagName = tagName[caseFix]();
-			return function(node){
-				return node.tagName == tagName;
-			}
-		}
-		function className(className){
-			var classNameSpaced = ' ' + className + ' ';
-			return function(node){
-				return node.className.indexOf(className) > -1 && (' ' + node.className + ' ').indexOf(classNameSpaced) > -1;
-			}
-		}
-		var attrComparators = {
-			"^=": function(attrValue, value){
-				return attrValue.indexOf(value) == 0;
-			},
-			"*=": function(attrValue, value){
-				return attrValue.indexOf(value) > -1;
-			},
-			"$=": function(attrValue, value){
-				return attrValue.substring(attrValue.length - value.length, attrValue.length) == value;
-			},
-			"~=": function(attrValue, value){
-				return (' ' + attrValue + ' ').indexOf(' ' + value + ' ') > -1;
-			},
-			"|=": function(attrValue, value){
-				return (attrValue + '-').indexOf(value + '-') == 0;
-			},
-			"=": function(attrValue, value){
-				return attrValue == value;
-			},
-			"": function(attrValue, value){
-				return true;
-			}
-		};
-		function attr(name, value, type){
-			if(value.match(/['"]/)){
-				// it is quoted, do an eval to parse the string (CSS and JS parsing are close enough)
-				value = eval(value);
-			}
-			var comparator = attrComparators[type || ""];
-			return function(node){
-				var attrValue = node.getAttribute(name);
-				return attrValue && comparator(attrValue, value);
-			}
-		}
-		function ancestor(matcher){
-			return function(node, root){
-				while((node = node.parentNode) != root){
-					if(matcher(node, root)){
-						return true;
-					}
-				}
-			};
-		}
-		function parent(matcher){
-			return function(node, root){
-				node = node.parentNode;
-				return matcher ? 
-					node != root && matcher(node, root)
-					: node == root;
-			};
-		}
-		var cache = {};
-		function and(matcher, next){
-			return matcher ?
-				function(node, root){
-					return next(node) && matcher(node, root);
-				}
-				: next;
-		}
-		return function(node, selector, root){
-			// this returns true or false based on if the node matches the selector (optionally within the given root)
-			var matcher = cache[selector]; // check to see if we have created a matcher function for the given selector
-			if(!matcher){
-				// create a matcher function for the given selector
-				// parse the selectors
-				if(selector.replace(/(?:\s*([> ])\s*)|(\.)?([\w-]+)|\[([\w-]+)\s*(.?=)?\s*([^\]]*)\]/g, function(t, combinator, type, value, attrName, attrType, attrValue){
-					if(value){
-						if(type == "."){
-							matcher = and(matcher, className(value));
-						}
-						else{
-							matcher = and(matcher, tag(value));
-						}
-					}
-					else if(combinator){
-						matcher = (combinator == " " ? ancestor : parent)(matcher);
-					}
-					else if(attrName){
-						matcher = and(matcher, attr(attrName, attrValue, attrType));
-					}
-					return "";
-				})){
-					throw new Error("Syntax error in query");
-				}
-				if(!matcher){
-					return true;
-				}
-				cache[selector] = matcher;
-			}
-			// now run the matcher function on the node
-			return matcher(node, root);
-		};
-	})();
-}
-if(!has("dom-qsa")){
-	var combine = function(selector, root){
-		// combined queries
-		selector = selector.split(/\s*,\s*/);
-		var indexed = [];
-		// add all results and keep unique ones, this only runs in IE, so we take advantage 
-		// of known IE features, particularly sourceIndex which is unique and allows us to 
-		// order the results 
-		for(var i = 0; i < selector.length; i++){
-			var results = liteEngine(selector[i], root);
-			for(var j = 0, l = results.length; j < l; j++){
-				var node = results[j];
-				indexed[node.sourceIndex] = node;
-			}
-		}
-		// now convert from a sparse array to a dense array
-		var totalResults = [];
-		for(i in indexed){
-			totalResults.push(indexed[i]);
-		}
-		return totalResults;
-	};
-}
-
-liteEngine.match = matchesSelector ? function(node, selector, root){
-	if(root){
-		// doesn't support three args, use rooted id trick
-		return useRoot(root, selector, function(query){
-			return matchesSelector.call(node, query);
-		});
-	}
-	// we have a native matchesSelector, use that
-	return matchesSelector.call(node, selector);
-} : jsMatchesSelector; // otherwise use the JS matches impl
-
-return liteEngine;
-});
+define(["../has", "../_base/kernel"], function(has, dojo){
+"use strict";
+// summary:
+//		A small lightweight query selector engine that implements CSS2.1 selectors 
+// 		minus pseudo-classes and the sibling combinator, plus CSS3 attribute selectors
+var testDiv = document.createElement("div");
+var matchesSelector = testDiv.matchesSelector || testDiv.webkitMatchesSelector || testDiv.mozMatchesSelector || testDiv.msMatchesSelector || testDiv.oMatchesSelector; // IE9, WebKit, Firefox have this, but not Opera yet
+var querySelectorAll = testDiv.querySelectorAll;
+has.add("dom-matches-selector", !!matchesSelector);
+has.add("dom-qsa", !!querySelectorAll); 
+
+// this is a simple query engine. It has handles basic selectors, and for simple
+// common selectors is extremely fast
+var liteEngine = function(selector, root){
+	if(combine && selector.indexOf(',') > -1){
+		return combine(selector, root);
+	}
+	var match = (querySelectorAll ? 
+		/^([\w]*)#([\w\-]+$)|^(\.)([\w\-\*]+$)|^(\w+$)/ : // this one only matches on simple queries where we can beat qSA with specific methods
+		/^([\w]*)#([\w\-]+)(?:\s+(.*))?$|(?:^|(>|.+\s+))([\w\-\*]+)(\S*$)/) // this one matches parts of the query that we can use to speed up manual filtering
+			.exec(selector);
+	root = root || document;
+	if(match){
+		// fast path regardless of whether or not querySelectorAll exists
+		if(match[2]){
+			// an #id
+			// use dojo.byId if available as it fixes the id retrieval in IE
+			var found = dojo.byId ? dojo.byId(match[2]) : document.getElementById(match[2]);
+			if(!found || (match[1] && match[1] != found.tagName.toLowerCase())){
+				// if there is a tag qualifer and it doesn't match, no matches
+				return [];
+			}
+			if(root != document){
+				// there is a root element, make sure we are a child of it
+				var parent = found;
+				while(parent != root){
+					parent = parent.parentNode;
+					if(!parent){
+						return [];
+					}
+				}
+			}
+			return match[3] ?
+					liteEngine(match[3], found) 
+					: [found];
+		}
+		if(match[3] && root.getElementsByClassName){
+			// a .class
+			return root.getElementsByClassName(match[4]);
+		}
+		var found;
+		if(match[5]){
+			// a tag
+			found = root.getElementsByTagName(match[5]);
+			if(match[4] || match[6]){
+				selector = (match[4] || "") + match[6];
+			}else{
+				// that was the entirety of the query, return results
+				return found;
+			}
+		}
+	}
+	if(querySelectorAll){
+		// qSA works strangely on Element-rooted queries
+		// We can work around this by specifying an extra ID on the root
+		// and working up from there (Thanks to Andrew Dupont for the technique)
+		// IE 8 doesn't work on object elements
+		if (root.nodeType === 1 && root.nodeName.toLowerCase() !== "object"){				
+			return useRoot(root, selector, root.querySelectorAll);
+		}else{
+			// we can use the native qSA
+			return root.querySelectorAll(selector);
+		}
+	}else if(!found){
+		// search all children and then filter
+		found = root.getElementsByTagName("*");
+	}
+	// now we filter the nodes that were found using the matchesSelector
+	var results = [];
+	for(var i = 0, l = found.length; i < l; i++){
+		var node = found[i];
+		if(node.nodeType == 1 && jsMatchesSelector(node, selector, root)){
+			// keep the nodes that match the selector
+			results.push(node);
+		}
+	}
+	return results;
+};
+var useRoot = function(context, query, method){
+	// this function creates a temporary id so we can do rooted qSA queries, this is taken from sizzle
+	var oldContext = context,
+		old = context.getAttribute( "id" ),
+		nid = old || "__dojo__",
+		hasParent = context.parentNode,
+		relativeHierarchySelector = /^\s*[+~]/.test( query );
+
+	if(relativeHierarchySelector && !hasParent){
+		return [];
+	}
+	if(!old){
+		context.setAttribute("id", nid);
+	}else{
+		nid = nid.replace(/'/g, "\\$&");
+	}
+	if(relativeHierarchySelector && hasParent){
+		context = context.parentNode;
+	}
+
+	try {
+		return method.call(context, "[id='" + nid + "'] " + query );
+	} finally {
+		if ( !old ) {
+			oldContext.removeAttribute( "id" );
+		}
+	}
+};
+
+if(!has("dom-matches-selector")){
+	var jsMatchesSelector = (function(){
+		// a JS implementation of CSS selector matching, first we start with the various handlers
+		var caseFix = testDiv.tagName == "div" ? "toLowerCase" : "toUpperCase";
+		function tag(tagName){
+			tagName = tagName[caseFix]();
+			return function(node){
+				return node.tagName == tagName;
+			}
+		}
+		function className(className){
+			var classNameSpaced = ' ' + className + ' ';
+			return function(node){
+				return node.className.indexOf(className) > -1 && (' ' + node.className + ' ').indexOf(classNameSpaced) > -1;
+			}
+		}
+		var attrComparators = {
+			"^=": function(attrValue, value){
+				return attrValue.indexOf(value) == 0;
+			},
+			"*=": function(attrValue, value){
+				return attrValue.indexOf(value) > -1;
+			},
+			"$=": function(attrValue, value){
+				return attrValue.substring(attrValue.length - value.length, attrValue.length) == value;
+			},
+			"~=": function(attrValue, value){
+				return (' ' + attrValue + ' ').indexOf(' ' + value + ' ') > -1;
+			},
+			"|=": function(attrValue, value){
+				return (attrValue + '-').indexOf(value + '-') == 0;
+			},
+			"=": function(attrValue, value){
+				return attrValue == value;
+			},
+			"": function(attrValue, value){
+				return true;
+			}
+		};
+		function attr(name, value, type){
+			if(value.match(/['"]/)){
+				// it is quoted, do an eval to parse the string (CSS and JS parsing are close enough)
+				value = eval(value);
+			}
+			var comparator = attrComparators[type || ""];
+			return function(node){
+				var attrValue = node.getAttribute(name);
+				return attrValue && comparator(attrValue, value);
+			}
+		}
+		function ancestor(matcher){
+			return function(node, root){
+				while((node = node.parentNode) != root){
+					if(matcher(node, root)){
+						return true;
+					}
+				}
+			};
+		}
+		function parent(matcher){
+			return function(node, root){
+				node = node.parentNode;
+				return matcher ? 
+					node != root && matcher(node, root)
+					: node == root;
+			};
+		}
+		var cache = {};
+		function and(matcher, next){
+			return matcher ?
+				function(node, root){
+					return next(node) && matcher(node, root);
+				}
+				: next;
+		}
+		return function(node, selector, root){
+			// this returns true or false based on if the node matches the selector (optionally within the given root)
+			var matcher = cache[selector]; // check to see if we have created a matcher function for the given selector
+			if(!matcher){
+				// create a matcher function for the given selector
+				// parse the selectors
+				if(selector.replace(/(?:\s*([> ])\s*)|(\.)?([\w-]+)|\[([\w-]+)\s*(.?=)?\s*([^\]]*)\]/g, function(t, combinator, type, value, attrName, attrType, attrValue){
+					if(value){
+						if(type == "."){
+							matcher = and(matcher, className(value));
+						}
+						else{
+							matcher = and(matcher, tag(value));
+						}
+					}
+					else if(combinator){
+						matcher = (combinator == " " ? ancestor : parent)(matcher);
+					}
+					else if(attrName){
+						matcher = and(matcher, attr(attrName, attrValue, attrType));
+					}
+					return "";
+				})){
+					throw new Error("Syntax error in query");
+				}
+				if(!matcher){
+					return true;
+				}
+				cache[selector] = matcher;
+			}
+			// now run the matcher function on the node
+			return matcher(node, root);
+		};
+	})();
+}
+if(!has("dom-qsa")){
+	var combine = function(selector, root){
+		// combined queries
+		selector = selector.split(/\s*,\s*/);
+		var indexed = [];
+		// add all results and keep unique ones, this only runs in IE, so we take advantage 
+		// of known IE features, particularly sourceIndex which is unique and allows us to 
+		// order the results 
+		for(var i = 0; i < selector.length; i++){
+			var results = liteEngine(selector[i], root);
+			for(var j = 0, l = results.length; j < l; j++){
+				var node = results[j];
+				indexed[node.sourceIndex] = node;
+			}
+		}
+		// now convert from a sparse array to a dense array
+		var totalResults = [];
+		for(i in indexed){
+			totalResults.push(indexed[i]);
+		}
+		return totalResults;
+	};
+}
+
+liteEngine.match = matchesSelector ? function(node, selector, root){
+	if(root){
+		// doesn't support three args, use rooted id trick
+		return useRoot(root, selector, function(query){
+			return matchesSelector.call(node, query);
+		});
+	}
+	// we have a native matchesSelector, use that
+	return matchesSelector.call(node, selector);
+} : jsMatchesSelector; // otherwise use the JS matches impl
+
+return liteEngine;
+});
diff --git a/store/api/Store.js b/store/api/Store.js
index 7f2533d..f16a836 100644
--- a/store/api/Store.js
+++ b/store/api/Store.js
@@ -1,297 +1,297 @@
-define(["dojo/_base/declare"], function(declare) {
-	// module:
-	//		dojo/store/api/Store
-	// summary:
-	//		The module defines the Dojo object store interface.
-
-var Store = declare("dojo.store.api.Store", null, {
-	// summary:
-	//		This is an abstract API that data provider implementations conform to.
-	//		This file defines methods signatures and intentionally leaves all the
-	//		methods unimplemented.  For more information on the dojo.store APIs,
-	//		please visit: http://dojotoolkit.org/reference-guide/dojo/store.html
-	//		Every method and property is optional, and is only needed if the functionality
-	//		it provides is required.
-	//		Every method may return a promise for the specified return value if the
-	//		execution of the operation is asynchronous (except
-	//		for query() which already defines an async return value).
-
-	// idProperty: String
-	//		If the store has a single primary key, this tndicates the property to use as the
-	//		identity property. The values of this property should be unique.
-	idProperty: "id",
-
-	// queryEngine: Function
-	//		If the store can be queried locally (on the client side in JS), this defines
-	//		the query engine to use for querying the data store.
-	//		This takes a query and query options and returns a function that can execute
-	//		the provided query on a JavaScript array. The queryEngine may be replace to
-	//		provide more sophisticated querying capabilities. For example:
-	//		| var query = store.queryEngine({foo:"bar"}, {count:10});
-	//		| query(someArray) -> filtered array
-	//		The returned query function may have a "matches" property that can be
-	//		used to determine if an object matches the query. For example:
-	//		| query.matches({id:"some-object", foo:"bar"}) -> true
-	//		| query.matches({id:"some-object", foo:"something else"}) -> false
-	queryEngine: null,
-
-	get: function(id){
-		// summary:
-		//		Retrieves an object by its identity
-		// id: Number
-		//		The identity to use to lookup the object
-		// returns: Object
-		//		The object in the store that matches the given id.
-	},
-	getIdentity: function(object){
-		// summary:
-		//		Returns an object's identity
-		// object: Object
-		//		The object to get the identity from
-		// returns: String|Number
-	},
-	put: function(object, directives){
-		// summary:
-		//		Stores an object
-		// object: Object
-		//		The object to store.
-		// directives: dojo.store.api.Store.PutDirectives?
-		//		Additional directives for storing objects.
-		// returns: Number|String
-	},
-	add: function(object, directives){
-		// summary:
-		//		Creates an object, throws an error if the object already exists
-		// object: Object
-		//		The object to store.
-		// directives: dojo.store.api.Store.PutDirectives?
-		//		Additional directives for creating objects.
-		// returns: Number|String
-	},
-	remove: function(id){
-		// summary:
-		//		Deletes an object by its identity
-		// id: Number
-		//		The identity to use to delete the object
-		delete this.index[id];
-		var data = this.data,
-			idProperty = this.idProperty;
-		for(var i = 0, l = data.length; i < l; i++){
-			if(data[i][idProperty] == id){
-				data.splice(i, 1);
-				return;
-			}
-		}
-	},
-	query: function(query, options){
-		// summary:
-		//		Queries the store for objects. This does not alter the store, but returns a
-		//		set of data from the store.
-		// query: String|Object|Function
-		//		The query to use for retrieving objects from the store.
-		// options: dojo.store.api.Store.QueryOptions
-		//		The optional arguments to apply to the resultset.
-		// returns: dojo.store.api.Store.QueryResults
-		//		The results of the query, extended with iterative methods.
-		//
-		// example:
-		//		Given the following store:
-		//
-		//	...find all items where "prime" is true:
-		//
-		//	|	store.query({ prime: true }).forEach(function(object){
-		//	|		// handle each object
-		//	|	});
-	},
-	transaction: function(){
-		// summary:
-		//		Starts a new transaction.
-		//		Note that a store user might not call transaction() prior to using put,
-		//		delete, etc. in which case these operations effectively could be thought of
-		//		as "auto-commit" style actions.
-		// returns: dojo.store.api.Store.Transaction
-		//		This represents the new current transaction.
-	},
-	getChildren: function(parent, options){
-		// summary:
-		//		Retrieves the children of an object.
-		// parent: Object
-		//		The object to find the children of.
-		// options: dojo.store.api.Store.QueryOptions?
-		//		Additional options to apply to the retrieval of the children.
-		// returns: dojo.store.api.Store.QueryResults
-		//		A result set of the children of the parent object.
-	},
-	getMetadata: function(object){
-		// summary:
-		//		Returns any metadata about the object. This may include attribution,
-		//		cache directives, history, or version information.
-		// object: Object
-		//		The object to return metadata for.
-		// returns: Object
-		//		An object containing metadata.
-	}
-});
-
-Store.PutDirectives = function(id, before, parent, overwrite){
-	// summary:
-	//		Directives passed to put() and add() handlers for guiding the update and
-	//		creation of stored objects.
-	// id: String|Number?
-	//		Indicates the identity of the object if a new object is created
-	// before: Object?
-	//		If the collection of objects in the store has a natural ordering,
-	//		this indicates that the created or updated object should be placed before the
-	//		object specified by the value of this property. A value of null indicates that the
-	//		object should be last.
-	// parent: Object?,
-	//		If the store is hierarchical (with single parenting) this property indicates the
-	//		new parent of the created or updated object.
-	// overwrite: Boolean?
-	//		If this is provided as a boolean it indicates that the object should or should not
-	//		overwrite an existing object. A value of true indicates that a new object
-	//		should not be created, the operation should update an existing object. A
-	//		value of false indicates that an existing object should not be updated, a new
-	//		object should be created (which is the same as an add() operation). When
-	//		this property is not provided, either an update or creation is acceptable.
-	this.id = id;
-	this.before = before;
-	this.parent = parent;
-	this.overwrite = overwrite;
-};
-
-Store.SortInformation = function(attribute, descending){
-	// summary:
-	//		An object describing what attribute to sort on, and the direction of the sort.
-	// attribute: String
-	//		The name of the attribute to sort on.
-	// descending: Boolean
-	//		The direction of the sort.  Default is false.
-	this.attribute = attribute;
-	this.descending = descending;
-};
-
-Store.QueryOptions = function(sort, start, count){
-	// summary:
-	//		Optional object with additional parameters for query results.
-	// sort: dojo.store.api.Store.SortInformation[]?
-	//		A list of attributes to sort on, as well as direction
-	//		For example:
-	//		| [{attribute:"price, descending: true}].
-	//		If the sort parameter is omitted, then the natural order of the store may be
-	//		applied if there is a natural order.
-	// start: Number?
-	//		The first result to begin iteration on
-	// count: Number?
-	//		The number of how many results should be returned.
-	this.sort = sort;
-	this.start = start;
-	this.count = count;
-};
-
-declare("dojo.store.api.Store.QueryResults", null, {
-	// summary:
-	//		This is an object returned from query() calls that provides access to the results
-	//		of a query. Queries may be executed asynchronously.
-
-	forEach: function(callback, thisObject){
-		// summary:
-		//		Iterates over the query results, based on
-		//		https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach.
-		//		Note that this may executed asynchronously. The callback may be called
-		//		after this function returns.
-		// callback:
-		//		Function that is called for each object in the query results
-		// thisObject:
-		//		The object to use as |this| in the callback.
-
-	},
-	filter: function(callback, thisObject){
-		// summary:
-		//		Filters the query results, based on
-		//		https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter.
-		//		Note that this may executed asynchronously. The callback may be called
-		//		after this function returns.
-		// callback:
-		//		Function that is called for each object in the query results
-		// thisObject:
-		//		The object to use as |this| in the callback.
-		// returns: dojo.store.api.Store.QueryResults
-	},
-	map: function(callback, thisObject){
-		// summary:
-		//		Maps the query results, based on
-		//		https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map.
-		//		Note that this may executed asynchronously. The callback may be called
-		//		after this function returns.
-		// callback:
-		//		Function that is called for each object in the query results
-		// thisObject:
-		//		The object to use as |this| in the callback.
-		// returns: dojo.store.api.Store.QueryResults
-	},
-	then: function(callback, errorHandler){
-		// summary:
-		//		This registers a callback for when the query is complete, if the query is asynchronous.
-		//		This is an optional method, and may not be present for synchronous queries.
-		// callback:
-		//		This is called when the query is completed successfully, and is passed a single argument
-		//		that is an array representing the query results.
-		// errorHandler:
-		//		This is called if the query failed, and is passed a single argument that is the error
-		//		for the failure.
-	},
-	observe: function(listener, includeAllUpdates){
-		// summary:
-		//		This registers a callback for notification of when data is modified in the query results.
-		//		This is an optional method, and is usually provided by dojo.store.Observable.
-		// listener: Function
-		//		The listener function is called when objects in the query results are modified
-		//		to affect the query result. The listener function is called with the following
-		// arguments:
-		//		| listener(object, removedFrom, insertedInto);
-		//		* The object parameter indicates the object that was create, modified, or deleted.
-		//		* The removedFrom parameter indicates the index in the result array where
-		//		the object used to be. If the value is -1, then the object is an addition to
-		//		this result set (due to a new object being created, or changed such that it
-		//		is a part of the result set).
-		//		* The insertedInto parameter indicates the index in the result array where
-		//		the object should be now. If the value is -1, then the object is a removal
-		//		from this result set (due to an object being deleted, or changed such that it
-		//		is not a part of the result set).
-		// includeAllUpdates:
-		//		This indicates whether or not to include object updates that do not affect
-		//		the inclusion or order of the object in the query results. By default this is false,
-		//		which means that if any object is updated in such a way that it remains
-		//		in the result set and it's position in result sets is not affected, then the listener
-		//		will not be fired.
-
-	},
-	// total: Number|Promise?
-	//		This property should be included in if the query options included the "count"
-	//		property limiting the result set. This property indicates the total number of objects
-	//		matching the query (as if "start" and "count" weren't present). This may be
-	//		a promise if the query is asynchronous.
-	total: 0
-});
-
-declare("dojo.store.api.Store.Transaction", null, {
-	// summary:
-	//		This is an object returned from transaction() calls that represents the current
-	//		transaction.
-
-	commit: function(){
-		// summary:
-		//		Commits the transaction. This may throw an error if it fails. Of if the operation
-		//		is asynchronous, it may return a promise that represents the eventual success
-		//		or failure of the commit.
-	},
-	abort: function(callback, thisObject){
-		// summary:
-		//		Aborts the transaction. This may throw an error if it fails. Of if the operation
-		//		is asynchronous, it may return a promise that represents the eventual success
-		//		or failure of the abort.
-	}
-});
-return Store;
-});
+define(["dojo/_base/declare"], function(declare) {
+	// module:
+	//		dojo/store/api/Store
+	// summary:
+	//		The module defines the Dojo object store interface.
+
+var Store = declare("dojo.store.api.Store", null, {
+	// summary:
+	//		This is an abstract API that data provider implementations conform to.
+	//		This file defines methods signatures and intentionally leaves all the
+	//		methods unimplemented.  For more information on the dojo.store APIs,
+	//		please visit: http://dojotoolkit.org/reference-guide/dojo/store.html
+	//		Every method and property is optional, and is only needed if the functionality
+	//		it provides is required.
+	//		Every method may return a promise for the specified return value if the
+	//		execution of the operation is asynchronous (except
+	//		for query() which already defines an async return value).
+
+	// idProperty: String
+	//		If the store has a single primary key, this tndicates the property to use as the
+	//		identity property. The values of this property should be unique.
+	idProperty: "id",
+
+	// queryEngine: Function
+	//		If the store can be queried locally (on the client side in JS), this defines
+	//		the query engine to use for querying the data store.
+	//		This takes a query and query options and returns a function that can execute
+	//		the provided query on a JavaScript array. The queryEngine may be replace to
+	//		provide more sophisticated querying capabilities. For example:
+	//		| var query = store.queryEngine({foo:"bar"}, {count:10});
+	//		| query(someArray) -> filtered array
+	//		The returned query function may have a "matches" property that can be
+	//		used to determine if an object matches the query. For example:
+	//		| query.matches({id:"some-object", foo:"bar"}) -> true
+	//		| query.matches({id:"some-object", foo:"something else"}) -> false
+	queryEngine: null,
+
+	get: function(id){
+		// summary:
+		//		Retrieves an object by its identity
+		// id: Number
+		//		The identity to use to lookup the object
+		// returns: Object
+		//		The object in the store that matches the given id.
+	},
+	getIdentity: function(object){
+		// summary:
+		//		Returns an object's identity
+		// object: Object
+		//		The object to get the identity from
+		// returns: String|Number
+	},
+	put: function(object, directives){
+		// summary:
+		//		Stores an object
+		// object: Object
+		//		The object to store.
+		// directives: dojo.store.api.Store.PutDirectives?
+		//		Additional directives for storing objects.
+		// returns: Number|String
+	},
+	add: function(object, directives){
+		// summary:
+		//		Creates an object, throws an error if the object already exists
+		// object: Object
+		//		The object to store.
+		// directives: dojo.store.api.Store.PutDirectives?
+		//		Additional directives for creating objects.
+		// returns: Number|String
+	},
+	remove: function(id){
+		// summary:
+		//		Deletes an object by its identity
+		// id: Number
+		//		The identity to use to delete the object
+		delete this.index[id];
+		var data = this.data,
+			idProperty = this.idProperty;
+		for(var i = 0, l = data.length; i < l; i++){
+			if(data[i][idProperty] == id){
+				data.splice(i, 1);
+				return;
+			}
+		}
+	},
+	query: function(query, options){
+		// summary:
+		//		Queries the store for objects. This does not alter the store, but returns a
+		//		set of data from the store.
+		// query: String|Object|Function
+		//		The query to use for retrieving objects from the store.
+		// options: dojo.store.api.Store.QueryOptions
+		//		The optional arguments to apply to the resultset.
+		// returns: dojo.store.api.Store.QueryResults
+		//		The results of the query, extended with iterative methods.
+		//
+		// example:
+		//		Given the following store:
+		//
+		//	...find all items where "prime" is true:
+		//
+		//	|	store.query({ prime: true }).forEach(function(object){
+		//	|		// handle each object
+		//	|	});
+	},
+	transaction: function(){
+		// summary:
+		//		Starts a new transaction.
+		//		Note that a store user might not call transaction() prior to using put,
+		//		delete, etc. in which case these operations effectively could be thought of
+		//		as "auto-commit" style actions.
+		// returns: dojo.store.api.Store.Transaction
+		//		This represents the new current transaction.
+	},
+	getChildren: function(parent, options){
+		// summary:
+		//		Retrieves the children of an object.
+		// parent: Object
+		//		The object to find the children of.
+		// options: dojo.store.api.Store.QueryOptions?
+		//		Additional options to apply to the retrieval of the children.
+		// returns: dojo.store.api.Store.QueryResults
+		//		A result set of the children of the parent object.
+	},
+	getMetadata: function(object){
+		// summary:
+		//		Returns any metadata about the object. This may include attribution,
+		//		cache directives, history, or version information.
+		// object: Object
+		//		The object to return metadata for.
+		// returns: Object
+		//		An object containing metadata.
+	}
+});
+
+Store.PutDirectives = function(id, before, parent, overwrite){
+	// summary:
+	//		Directives passed to put() and add() handlers for guiding the update and
+	//		creation of stored objects.
+	// id: String|Number?
+	//		Indicates the identity of the object if a new object is created
+	// before: Object?
+	//		If the collection of objects in the store has a natural ordering,
+	//		this indicates that the created or updated object should be placed before the
+	//		object specified by the value of this property. A value of null indicates that the
+	//		object should be last.
+	// parent: Object?,
+	//		If the store is hierarchical (with single parenting) this property indicates the
+	//		new parent of the created or updated object.
+	// overwrite: Boolean?
+	//		If this is provided as a boolean it indicates that the object should or should not
+	//		overwrite an existing object. A value of true indicates that a new object
+	//		should not be created, the operation should update an existing object. A
+	//		value of false indicates that an existing object should not be updated, a new
+	//		object should be created (which is the same as an add() operation). When
+	//		this property is not provided, either an update or creation is acceptable.
+	this.id = id;
+	this.before = before;
+	this.parent = parent;
+	this.overwrite = overwrite;
+};
+
+Store.SortInformation = function(attribute, descending){
+	// summary:
+	//		An object describing what attribute to sort on, and the direction of the sort.
+	// attribute: String
+	//		The name of the attribute to sort on.
+	// descending: Boolean
+	//		The direction of the sort.  Default is false.
+	this.attribute = attribute;
+	this.descending = descending;
+};
+
+Store.QueryOptions = function(sort, start, count){
+	// summary:
+	//		Optional object with additional parameters for query results.
+	// sort: dojo.store.api.Store.SortInformation[]?
+	//		A list of attributes to sort on, as well as direction
+	//		For example:
+	//		| [{attribute:"price, descending: true}].
+	//		If the sort parameter is omitted, then the natural order of the store may be
+	//		applied if there is a natural order.
+	// start: Number?
+	//		The first result to begin iteration on
+	// count: Number?
+	//		The number of how many results should be returned.
+	this.sort = sort;
+	this.start = start;
+	this.count = count;
+};
+
+declare("dojo.store.api.Store.QueryResults", null, {
+	// summary:
+	//		This is an object returned from query() calls that provides access to the results
+	//		of a query. Queries may be executed asynchronously.
+
+	forEach: function(callback, thisObject){
+		// summary:
+		//		Iterates over the query results, based on
+		//		https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/forEach.
+		//		Note that this may executed asynchronously. The callback may be called
+		//		after this function returns.
+		// callback:
+		//		Function that is called for each object in the query results
+		// thisObject:
+		//		The object to use as |this| in the callback.
+
+	},
+	filter: function(callback, thisObject){
+		// summary:
+		//		Filters the query results, based on
+		//		https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter.
+		//		Note that this may executed asynchronously. The callback may be called
+		//		after this function returns.
+		// callback:
+		//		Function that is called for each object in the query results
+		// thisObject:
+		//		The object to use as |this| in the callback.
+		// returns: dojo.store.api.Store.QueryResults
+	},
+	map: function(callback, thisObject){
+		// summary:
+		//		Maps the query results, based on
+		//		https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map.
+		//		Note that this may executed asynchronously. The callback may be called
+		//		after this function returns.
+		// callback:
+		//		Function that is called for each object in the query results
+		// thisObject:
+		//		The object to use as |this| in the callback.
+		// returns: dojo.store.api.Store.QueryResults
+	},
+	then: function(callback, errorHandler){
+		// summary:
+		//		This registers a callback for when the query is complete, if the query is asynchronous.
+		//		This is an optional method, and may not be present for synchronous queries.
+		// callback:
+		//		This is called when the query is completed successfully, and is passed a single argument
+		//		that is an array representing the query results.
+		// errorHandler:
+		//		This is called if the query failed, and is passed a single argument that is the error
+		//		for the failure.
+	},
+	observe: function(listener, includeAllUpdates){
+		// summary:
+		//		This registers a callback for notification of when data is modified in the query results.
+		//		This is an optional method, and is usually provided by dojo.store.Observable.
+		// listener: Function
+		//		The listener function is called when objects in the query results are modified
+		//		to affect the query result. The listener function is called with the following
+		// arguments:
+		//		| listener(object, removedFrom, insertedInto);
+		//		* The object parameter indicates the object that was create, modified, or deleted.
+		//		* The removedFrom parameter indicates the index in the result array where
+		//		the object used to be. If the value is -1, then the object is an addition to
+		//		this result set (due to a new object being created, or changed such that it
+		//		is a part of the result set).
+		//		* The insertedInto parameter indicates the index in the result array where
+		//		the object should be now. If the value is -1, then the object is a removal
+		//		from this result set (due to an object being deleted, or changed such that it
+		//		is not a part of the result set).
+		// includeAllUpdates:
+		//		This indicates whether or not to include object updates that do not affect
+		//		the inclusion or order of the object in the query results. By default this is false,
+		//		which means that if any object is updated in such a way that it remains
+		//		in the result set and it's position in result sets is not affected, then the listener
+		//		will not be fired.
+
+	},
+	// total: Number|Promise?
+	//		This property should be included in if the query options included the "count"
+	//		property limiting the result set. This property indicates the total number of objects
+	//		matching the query (as if "start" and "count" weren't present). This may be
+	//		a promise if the query is asynchronous.
+	total: 0
+});
+
+declare("dojo.store.api.Store.Transaction", null, {
+	// summary:
+	//		This is an object returned from transaction() calls that represents the current
+	//		transaction.
+
+	commit: function(){
+		// summary:
+		//		Commits the transaction. This may throw an error if it fails. Of if the operation
+		//		is asynchronous, it may return a promise that represents the eventual success
+		//		or failure of the commit.
+	},
+	abort: function(callback, thisObject){
+		// summary:
+		//		Aborts the transaction. This may throw an error if it fails. Of if the operation
+		//		is asynchronous, it may return a promise that represents the eventual success
+		//		or failure of the abort.
+	}
+});
+return Store;
+});
diff --git a/tests/aspect.js b/tests/aspect.js
index fa739d9..be1bd6e 100644
--- a/tests/aspect.js
+++ b/tests/aspect.js
@@ -1,119 +1,119 @@
-dojo.provide("dojo.tests.aspect");
-
-var aspect = dojo.require("dojo.aspect");
-
-doh.register("tests.aspect",
-	[
-		function before(t){
-			var order = [];
-			var obj = {
-				method: function(a){
-					order.push(a);
-				}
-			};
-			var signal = aspect.before(obj, "method", function(a){
-				order.push(a);
-				return [a+1];
-			});
-			obj.method(0);
-			obj.method(2);
-			var signal2 = aspect.before(obj, "method", function(a){
-				order.push(a);
-				return [a+1];
-			});
-			obj.method(4);
-			signal.remove();
-			obj.method(7);
-			signal2.remove();
-			obj.method(9);
-			t.is(order, [0,1,2,3,4,5,6,7,8,9]);
-		},
-
-		function after(t){
-			var order = [];
-			var obj = {
-				method: function(a){
-					order.push(a);
-					return a+1;
-				}
-			};
-			var signal = aspect.after(obj, "method", function(a){
-				order.push(0);
-				return a+1;
-			});
-			obj.method(0);
-			var signal2 = aspect.after(obj, "method", function(a){
-				order.push(a);
-			});
-			obj.method(3);
-			var signal3 = aspect.after(obj, "method", function(a){
-				order.push(3);
-			}, true);
-			obj.method(3);
-			signal2.remove();
-			obj.method(6);
-			signal3.remove();
-			var signal4 = aspect.after(obj, "method", function(a){
-				order.push(4);
-			}, true);
-			signal.remove();
-			obj.method(7);
-			t.is(order, [0, 0, 3, 0, 5, 3, 0, 5, 3, 6, 0, 3, 7, 4]);
-		},
-		function around(t){
-			var order = [];
-			var obj = {
-				method: function(a){
-					order.push(a);
-					return a+1;
-				}
-			};
-			var beforeSignal = aspect.before(obj, "method", function(a){
-				order.push(a);
-			});
-			var signal = aspect.around(obj, "method", function(original){
-				return function(a){
-					a= a + 1;
-					a = original(a);
-					order.push(a);
-					return a+1;
-				}
-			});
-			order.push(obj.method(0));
-			obj.method(4);
-			t.is(order, [0,1,2,3,4,5,6]);
-		},
-		function delegation(t){
-			var order = [];
-			var proto = {
-				foo: function(x){
-					order.push(x);
-					return x;
-				},
-				bar: function(){
-				}
-			};
-			aspect.after(proto, "foo", function(x){
-				order.push(x + 1);
-				return x;
-			});
-			aspect.after(proto, "bar", function(x){
-				t.t(this.isInstance);
-			});
-			proto.foo(0);
-			function Class(){
-			}
-			Class.prototype = proto;
-			var instance = new Class();
-			instance.isInstance = true;
-			aspect.after(instance, "foo", function(x){
-				order.push(x + 2);
-				return x;
-			});
-			instance.bar();
-			instance.foo(2);
-			proto.foo(5);
-			t.is(order, [0,1,2,3,4,5,6]);
-		}
-	]
-);
+dojo.provide("dojo.tests.aspect");
+
+var aspect = dojo.require("dojo.aspect");
+
+doh.register("tests.aspect",
+	[
+		function before(t){
+			var order = [];
+			var obj = {
+				method: function(a){
+					order.push(a);
+				}
+			};
+			var signal = aspect.before(obj, "method", function(a){
+				order.push(a);
+				return [a+1];
+			});
+			obj.method(0);
+			obj.method(2);
+			var signal2 = aspect.before(obj, "method", function(a){
+				order.push(a);
+				return [a+1];
+			});
+			obj.method(4);
+			signal.remove();
+			obj.method(7);
+			signal2.remove();
+			obj.method(9);
+			t.is(order, [0,1,2,3,4,5,6,7,8,9]);
+		},
+
+		function after(t){
+			var order = [];
+			var obj = {
+				method: function(a){
+					order.push(a);
+					return a+1;
+				}
+			};
+			var signal = aspect.after(obj, "method", function(a){
+				order.push(0);
+				return a+1;
+			});
+			obj.method(0);
+			var signal2 = aspect.after(obj, "method", function(a){
+				order.push(a);
+			});
+			obj.method(3);
+			var signal3 = aspect.after(obj, "method", function(a){
+				order.push(3);
+			}, true);
+			obj.method(3);
+			signal2.remove();
+			obj.method(6);
+			signal3.remove();
+			var signal4 = aspect.after(obj, "method", function(a){
+				order.push(4);
+			}, true);
+			signal.remove();
+			obj.method(7);
+			t.is(order, [0, 0, 3, 0, 5, 3, 0, 5, 3, 6, 0, 3, 7, 4]);
+		},
+		function around(t){
+			var order = [];
+			var obj = {
+				method: function(a){
+					order.push(a);
+					return a+1;
+				}
+			};
+			var beforeSignal = aspect.before(obj, "method", function(a){
+				order.push(a);
+			});
+			var signal = aspect.around(obj, "method", function(original){
+				return function(a){
+					a= a + 1;
+					a = original(a);
+					order.push(a);
+					return a+1;
+				}
+			});
+			order.push(obj.method(0));
+			obj.method(4);
+			t.is(order, [0,1,2,3,4,5,6]);
+		},
+		function delegation(t){
+			var order = [];
+			var proto = {
+				foo: function(x){
+					order.push(x);
+					return x;
+				},
+				bar: function(){
+				}
+			};
+			aspect.after(proto, "foo", function(x){
+				order.push(x + 1);
+				return x;
+			});
+			aspect.after(proto, "bar", function(x){
+				t.t(this.isInstance);
+			});
+			proto.foo(0);
+			function Class(){
+			}
+			Class.prototype = proto;
+			var instance = new Class();
+			instance.isInstance = true;
+			aspect.after(instance, "foo", function(x){
+				order.push(x + 2);
+				return x;
+			});
+			instance.bar();
+			instance.foo(2);
+			proto.foo(5);
+			t.is(order, [0,1,2,3,4,5,6]);
+		}
+	]
+);
diff --git a/tests/json.js b/tests/json.js
index 1d15cb1..ee777a7 100644
--- a/tests/json.js
+++ b/tests/json.js
@@ -1,166 +1,166 @@
-define(["../main", "doh", "../json"], function(dojo, doh, JSON){
-
-	var mustThrow = function(json){
-		try{
-			JSON.parse(json, true);
-		}catch(e){
-			return;
-		}
-		throw new Error("Invalid JSON " + json + " should have been rejected");
-	};
-
-	doh.register("tests.json", [
-		// all tests below are taken from #4.2 of the CSS3 Color Module
-		function simpleString(t){ t.is("bar", JSON.parse('{"foo":"bar"}').foo)},
-		function simpleTrue(t){ t.is(true, JSON.parse('{"foo":true}').foo)},
-		function simpleFalse(t){ t.is(false, JSON.parse('{"foo":false}').foo)},
-		function simpleNull(t){ t.is(null, JSON.parse('{"foo":null}').foo)},
-		function simpleNumber(t){ t.is(3.3, JSON.parse('{"foo":3.3}', true).foo)},
-		function strictString(t){ t.is("bar", JSON.parse('{"foo":"bar"}', true).foo)},
-		function strictStringEsc(t){ t.is("b\n\t\"ar()", JSON.parse('{"foo":"b\\n\\t\\"ar()"}', true).foo)},
-		function strictTrue(t){ t.is(true, JSON.parse('{"foo":true}', true).foo)},
-		function strictFalse(t){ t.is(false, JSON.parse('{"foo":false}', true).foo)},
-		function strictNull(t){ t.is(null, JSON.parse('{"foo":null}', true).foo)},
-		function strictNumber(t){ t.is(3.3, JSON.parse('{"foo":3.3}', true).foo)},
-		function strictNumberNeg(t){ t.is(-3.3, JSON.parse('{"foo":-3.3}', true).foo)},
-		function exponentNegative(t){ t.is(3.3e-33, JSON.parse('{"foo":3.3e-33}', true).foo)},
-		function exponent(t){ t.is(3.3e33, JSON.parse('{"foo":3.3e33}', true).foo)},
-		function array(t){ t.is(3, JSON.parse('{"foo":[3,true,[]]}', true).foo[0])},
-		function badCall(t){ mustThrow('{"foo":alert()}')},
-		function badMath(t){ mustThrow('{"foo":3+4}')},
-		function badIndex(t){ mustThrow('{"foo":"bar"}[3]')},
-		function badKey(t){ mustThrow('{foo:"bar"}')},
-		//function badKey2(t){ mustThrow('{2:"bar"}')},
-		function badUnbalanced(t){ mustThrow('[')},
-		function badUnbalanced2(t){ mustThrow('}')},
-		function badType(t){ mustThrow('["foo":"bar"]')},
-		function badUnbalanced2(t){ mustThrow('}')},
-		function serializeString(t){ t.is('{"foo":"bar"}', JSON.stringify({"foo":"bar"}))},
-		function serializeNull(t){ t.is('{"foo":null}', JSON.stringify({"foo":null}))},
-		function serializeFunction(t){ t.is('{}', JSON.stringify({"foo":function(){}}))},
-		function serializeNaN(t){ t.is('{"foo":null}', JSON.stringify({"foo":NaN}))},
-		function serializeInfinity(t){ t.is('{"foo":null}', JSON.stringify({"foo":Infinity}))},
-		// there is differences in how many decimals of accuracies in seconds in how Dates are serialized between browsers
-		function serializeDate(t){ t.t(/1970-01-01T00:00:00.*Z/.test(JSON.parse(JSON.stringify({"foo":new Date(1)})).foo));},
-		function serializeCircular(t){
-			try{
-				var a = {};
-				a.a = a;
-				console.log("circular: " + JSON.stringify(a));
-			}catch(e){
-				return;
-			}
-			throw new Error("stringify must throw for circular references");
-
-		},
-		/*Apparently Firefox doesn't pass the key to the toJSON method*/
-		function serializeToJSON(t){ t.is('{"foo":{"name":"value"}}', JSON.stringify({foo:{toJSON:function(key){return {name:"value"};}}}))}
-	]);
-
-var smallDataSet = {
-	prop1: null,
-	prop2: true,
-	prop3: [],
-	prop4: 3.4325222223332266,
-	prop5: 10003,
-	prop6: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper",
-	prop7: "sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum",
-	prop8: "lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus",
-	prop9: "venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie",
-	prop10: "tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus." +
-		"Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet." +
-		"Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc," +
-		"ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa" +
-		"bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque." +
-		"Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam" +
-		"purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing" +
-		"nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend" +
-		"leo vitae ligula. Nulla facilisi."
-};
-var smallJson = JSON.stringify(smallDataSet);
-
-var i, mediumDataSet = [];
-for(i = 0; i < 20; i++){
-	mediumDataSet.push({
-		prop1: null,
-		prop2: true,
-		prop3: false,
-		prop4: 3.4325222223332266 - i,
-		prop5: 10003 + i,
-		prop6: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper",
-		prop7: "sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum",
-		prop8: "lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus",
-		prop9: "venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie",
-		prop10: "tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus." +
-			"Aliquam vitae enim."
-	});
-}
-var mediumJson = JSON.stringify(mediumDataSet);
-
-var largeDataSet = [];
-for(i = 0; i < 100; i++){
-	largeDataSet.push({
-		prop1: null,
-		prop2: true,
-		prop3: false,
-		prop4: 3.4325222223332266 - i,
-		prop5: ["Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam" +
-			"purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing",
-			"nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend" +
-			"leo vitae ligula. Nulla facilisi."
-		],
-		prop6: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper",
-		prop7: "sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum",
-		prop8: "lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus",
-		prop9: "venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie",
-	prop10: "tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus." +
-		"Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet." +
-		"Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc," +
-		"ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa" +
-		"bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque."
-	});
-}
-var largeJson = JSON.stringify(largeDataSet);
-
-doh.register("tests.json.performance", [
-		// all tests below are taken from #4.2 of the CSS3 Color Module
-		function small(){
-			var i = 10000;
-			while(i-->0){
-				var result = JSON.parse(smallJson);
-			}
-		},
-		function strictSmall(){
-			var i = 10000;
-			while(i-->0){
-				var result = JSON.parse(smallJson, true);
-			}
-		},
-		function medium(){
-			var i = 1000;
-			while(i-->0){
-				var result = JSON.parse(mediumJson);
-			}
-		},
-		function strictMedium(){
-			var i = 1000;
-			while(i-->0){
-				var result = JSON.parse(mediumJson, true);
-			}
-		},
-		function large(){
-			var i = 100;
-			while(i-->0){
-				var result = JSON.parse(largeJson);
-			}
-		},
-		function strictLarge(){
-			var i = 100;
-			while(i-->0){
-				var result = JSON.parse(largeJson, true);
-			}
-		}
-	]);
-
-});
-
+define(["../main", "doh", "../json"], function(dojo, doh, JSON){
+
+	var mustThrow = function(json){
+		try{
+			JSON.parse(json, true);
+		}catch(e){
+			return;
+		}
+		throw new Error("Invalid JSON " + json + " should have been rejected");
+	};
+
+	doh.register("tests.json", [
+		// all tests below are taken from #4.2 of the CSS3 Color Module
+		function simpleString(t){ t.is("bar", JSON.parse('{"foo":"bar"}').foo)},
+		function simpleTrue(t){ t.is(true, JSON.parse('{"foo":true}').foo)},
+		function simpleFalse(t){ t.is(false, JSON.parse('{"foo":false}').foo)},
+		function simpleNull(t){ t.is(null, JSON.parse('{"foo":null}').foo)},
+		function simpleNumber(t){ t.is(3.3, JSON.parse('{"foo":3.3}', true).foo)},
+		function strictString(t){ t.is("bar", JSON.parse('{"foo":"bar"}', true).foo)},
+		function strictStringEsc(t){ t.is("b\n\t\"ar()", JSON.parse('{"foo":"b\\n\\t\\"ar()"}', true).foo)},
+		function strictTrue(t){ t.is(true, JSON.parse('{"foo":true}', true).foo)},
+		function strictFalse(t){ t.is(false, JSON.parse('{"foo":false}', true).foo)},
+		function strictNull(t){ t.is(null, JSON.parse('{"foo":null}', true).foo)},
+		function strictNumber(t){ t.is(3.3, JSON.parse('{"foo":3.3}', true).foo)},
+		function strictNumberNeg(t){ t.is(-3.3, JSON.parse('{"foo":-3.3}', true).foo)},
+		function exponentNegative(t){ t.is(3.3e-33, JSON.parse('{"foo":3.3e-33}', true).foo)},
+		function exponent(t){ t.is(3.3e33, JSON.parse('{"foo":3.3e33}', true).foo)},
+		function array(t){ t.is(3, JSON.parse('{"foo":[3,true,[]]}', true).foo[0])},
+		function badCall(t){ mustThrow('{"foo":alert()}')},
+		function badMath(t){ mustThrow('{"foo":3+4}')},
+		function badIndex(t){ mustThrow('{"foo":"bar"}[3]')},
+		function badKey(t){ mustThrow('{foo:"bar"}')},
+		//function badKey2(t){ mustThrow('{2:"bar"}')},
+		function badUnbalanced(t){ mustThrow('[')},
+		function badUnbalanced2(t){ mustThrow('}')},
+		function badType(t){ mustThrow('["foo":"bar"]')},
+		function badUnbalanced2(t){ mustThrow('}')},
+		function serializeString(t){ t.is('{"foo":"bar"}', JSON.stringify({"foo":"bar"}))},
+		function serializeNull(t){ t.is('{"foo":null}', JSON.stringify({"foo":null}))},
+		function serializeFunction(t){ t.is('{}', JSON.stringify({"foo":function(){}}))},
+		function serializeNaN(t){ t.is('{"foo":null}', JSON.stringify({"foo":NaN}))},
+		function serializeInfinity(t){ t.is('{"foo":null}', JSON.stringify({"foo":Infinity}))},
+		// there is differences in how many decimals of accuracies in seconds in how Dates are serialized between browsers
+		function serializeDate(t){ t.t(/1970-01-01T00:00:00.*Z/.test(JSON.parse(JSON.stringify({"foo":new Date(1)})).foo));},
+		function serializeCircular(t){
+			try{
+				var a = {};
+				a.a = a;
+				console.log("circular: " + JSON.stringify(a));
+			}catch(e){
+				return;
+			}
+			throw new Error("stringify must throw for circular references");
+
+		},
+		/*Apparently Firefox doesn't pass the key to the toJSON method*/
+		function serializeToJSON(t){ t.is('{"foo":{"name":"value"}}', JSON.stringify({foo:{toJSON:function(key){return {name:"value"};}}}))}
+	]);
+
+var smallDataSet = {
+	prop1: null,
+	prop2: true,
+	prop3: [],
+	prop4: 3.4325222223332266,
+	prop5: 10003,
+	prop6: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper",
+	prop7: "sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum",
+	prop8: "lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus",
+	prop9: "venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie",
+	prop10: "tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus." +
+		"Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet." +
+		"Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc," +
+		"ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa" +
+		"bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque." +
+		"Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam" +
+		"purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing" +
+		"nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend" +
+		"leo vitae ligula. Nulla facilisi."
+};
+var smallJson = JSON.stringify(smallDataSet);
+
+var i, mediumDataSet = [];
+for(i = 0; i < 20; i++){
+	mediumDataSet.push({
+		prop1: null,
+		prop2: true,
+		prop3: false,
+		prop4: 3.4325222223332266 - i,
+		prop5: 10003 + i,
+		prop6: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper",
+		prop7: "sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum",
+		prop8: "lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus",
+		prop9: "venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie",
+		prop10: "tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus." +
+			"Aliquam vitae enim."
+	});
+}
+var mediumJson = JSON.stringify(mediumDataSet);
+
+var largeDataSet = [];
+for(i = 0; i < 100; i++){
+	largeDataSet.push({
+		prop1: null,
+		prop2: true,
+		prop3: false,
+		prop4: 3.4325222223332266 - i,
+		prop5: ["Mauris ipsum est, pharetra semper, pharetra in, viverra quis, tellus. Etiam" +
+			"purus. Quisque egestas, tortor ac cursus lacinia, felis leo adipiscing",
+			"nisi, et rhoncus elit dolor eget eros. Fusce ut quam. Suspendisse eleifend" +
+			"leo vitae ligula. Nulla facilisi."
+		],
+		prop6: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean semper",
+		prop7: "sagittis velit. Cras in mi. Duis porta mauris ut ligula. Proin porta rutrum",
+		prop8: "lacus. Etiam consequat scelerisque quam. Nulla facilisi. Maecenas luctus",
+		prop9: "venenatis nulla. In sit amet dui non mi semper iaculis. Sed molestie",
+	prop10: "tortor at ipsum. Morbi dictum rutrum magna. Sed vitae risus." +
+		"Aliquam vitae enim. Duis scelerisque metus auctor est venenatis imperdiet." +
+		"Fusce dignissim porta augue. Nulla vestibulum. Integer lorem nunc," +
+		"ullamcorper a, commodo ac, malesuada sed, dolor. Aenean id mi in massa" +
+		"bibendum suscipit. Integer eros. Nullam suscipit mauris. In pellentesque."
+	});
+}
+var largeJson = JSON.stringify(largeDataSet);
+
+doh.register("tests.json.performance", [
+		// all tests below are taken from #4.2 of the CSS3 Color Module
+		function small(){
+			var i = 10000;
+			while(i-->0){
+				var result = JSON.parse(smallJson);
+			}
+		},
+		function strictSmall(){
+			var i = 10000;
+			while(i-->0){
+				var result = JSON.parse(smallJson, true);
+			}
+		},
+		function medium(){
+			var i = 1000;
+			while(i-->0){
+				var result = JSON.parse(mediumJson);
+			}
+		},
+		function strictMedium(){
+			var i = 1000;
+			while(i-->0){
+				var result = JSON.parse(mediumJson, true);
+			}
+		},
+		function large(){
+			var i = 100;
+			while(i-->0){
+				var result = JSON.parse(largeJson);
+			}
+		},
+		function strictLarge(){
+			var i = 100;
+			while(i-->0){
+				var result = JSON.parse(largeJson, true);
+			}
+		}
+	]);
+
+});
+
diff --git a/tests/on.js b/tests/on.js
index 7091889..73adabb 100644
--- a/tests/on.js
+++ b/tests/on.js
@@ -1,229 +1,229 @@
-dojo.provide("dojo.tests.on");
-
-var on = dojo.require("dojo.on");
-var has = dojo.require("dojo.has");
-var topic = dojo.require("dojo.topic");
-var Evented = dojo.require("dojo.Evented");
-doh.register("tests.on",
-	[
-		function object(t){
-			var order = [];
-			var obj = new dojo.Evented();
-			obj.oncustom = function(event){
-				order.push(event.a);
-				return event.a+1;
-			};
-			var signal = on.pausable(obj, "custom", function(event){
-				order.push(0);
-				return event.a+1;
-			});
-			obj.oncustom({a:0});
-			var signal2 = on(obj, "custom, foo", function(event){
-				order.push(event.a);
-			});
-			on.emit(obj, "custom", {
-				a: 3
-			});
-			signal.pause();
-			var signal3 = on(obj, "custom", function(a){
-				order.push(3);
-			}, true);
-			on.emit(obj, "custom", {
-				a: 3
-			});
-			signal2.remove();
-			signal.resume();
-			on.emit(obj, "custom", {
-				a: 6
-			});
-			signal3.remove();
-			var signal4 = on(obj, "foo, custom", function(a){
-				order.push(4);
-			}, true);
-			signal.remove();
-			on.emit(obj, "custom", {
-				a: 7
-			});
-			t.is(order, [0,0,3,0,3,3,3,3,6,0,3,7,4]);
-		},
-		function once(t){
-			var order = [];
-			var obj = new dojo.Evented();
-			obj.on("custom", function(event){
-				order.push(event.a);
-			});
-			var signal = on.once(obj, "custom", function(event){
-				order.push(1);
-			});
-			obj.emit("custom",{a:0});
-			obj.oncustom({a:2}); // should call original method, but not listener
-			t.is(order, [0,1,2]);
-		},
-		function dom(t){
-			var div = document.body.appendChild(document.createElement("div"));
-			var span = div.appendChild(document.createElement("span"));
-			var order = [];
-			var signal = on(div,"custom", function(event){
-				order.push(event.a);
-				event.addedProp += "ue";
-			});
-			on(span,"custom", function(event){
-				event.addedProp = "val";
-			});
-			on.emit(div, "custom", {
-				target: div,
-				currentTarget:div,
-				relatedTarget: div,
-				a: 0
-			});
-			on.emit(div, "otherevent", {
-				a: 0
-			});
-			t.is(on.emit(span, "custom", {
-				a: 1,
-				bubbles: true,
-				cancelable: true
-			}).addedProp, "value");
-			t.t(on.emit(span, "custom", {
-				a: 1,
-				bubbles: false,
-				cancelable: true
-			}));
-			var signal2 = on.pausable(div,"custom", function(event){
-				order.push(event.a + 1);
-				event.preventDefault();
-			});
-			t.f(on.emit(span, "custom", {
-				a: 2,
-				bubbles: true,
-				cancelable: true
-			}));
-			signal2.pause();
-			t.is(on.emit(span, "custom", {
-				a: 4,
-				bubbles: true,
-				cancelable: true
-			}).type, "custom");
-			signal2.resume();
-			signal.remove();
-			t.f(on.emit(span, "custom", {
-				a: 4,
-				bubbles: true,
-				cancelable: true
-			}));
-			on(span, "custom", function(event){
-				order.push(6);
-				event.stopPropagation();
-			});
-			t.t(on.emit(span, "custom", {
-				a: 1,
-				bubbles: true,
-				cancelable: true
-			}));
-			var button = div.appendChild(document.createElement("button"));
-			// make sure we are propagating natively created events too
-			signal = on(div, "click", function(){
-				order.push(7);
-			});
-			button.click();
-			signal.remove();
-			// test out event delegation
-			if(dojo.query){
-				// if dojo.query is loaded, test event delegation
-				on(div, "button:click", function(){
-					order.push(8);
-				});
-				button.click();
-			}else{//just pass then
-				order.push(8);
-			}
-			t.is(order, [0, 1, 2, 3, 4, 5, 6, 7, 8]);
-		},
-/*
- This only works if the test page has the focus, so you can enable if you want to test focus functionality and allow the test page to have focus  
- 		function focus(t){
-			var div = document.body.appendChild(document.createElement("div"));
-			var input = div.appendChild(document.createElement("input"));
-			var order = [];
-			var signal = on(div,"input:focusin", function(event){
-				order.push('in');
-			});
-			var signal = on(div,"input:focusout", function(event){
-				order.push('out');
-			});
-			var otherInput = document.body.appendChild(document.createElement("input"));
-			input.focus();
-			otherInput.focus();
-			d = new doh.Deferred();
-			setTimeout(function(){
-				t.is(['in', 'out'], order);
-				d.callback(true);
-			}, 1);
-			return d;
-		},*/
-		function extensionEvent(t){
-			var div = document.body.appendChild(document.createElement("div"));
-			var span = div.appendChild(document.createElement("span"));
-			span.setAttribute("foo", 2);
-			var order = [];
-			var customEvent = function(target, listener){
-				return on(target, "custom", listener);
-			};
-			var signal = on(div, customEvent, function(event){
-				order.push(event.a);
-			});
-			var signal = on(div, on.selector("span", customEvent), function(event){
-				order.push(+this.getAttribute("foo"));
-			});
-			on.emit(div, "custom", {
-				a: 0
-			});
-			// should trigger selector
-			t.t(on.emit(span, "custom", {
-				a: 1,
-				bubbles: true,
-				cancelable: true
-			}));
-			// shouldn't trigger selector
-			t.t(on.emit(div, "custom", {
-				a: 3,
-				bubbles: true,
-				cancelable: true
-			}));
-			t.is(order, [0, 1, 2, 3]);
-		},
-		function testEvented(t){
-			var MyClass = dojo.declare([Evented],{
-
-			});
-			var order = [];
-			myObject = new MyClass;
-			myObject.on("custom", function(event){
-				order.push(event.a);
-			});
-			myObject.emit("custom", {a:0});
-			t.is(order, [0]);
-		},
-		function pubsub(t){
-			var fooCount = 0;
-			topic.subscribe("/test/foo", function(event, secondArg){
-				t.is("value", event.foo);
-				t.is("second", secondArg);
-				fooCount++;
-			});
-			topic.publish("/test/foo", {foo: "value"}, "second");
-			t.is(1, fooCount);
-		},
-		function touch(t){
-			console.log("has", has);
-			if(has("touch")){
-				var div = document.body.appendChild(document.createElement("div"));
-				on(div, "touchstart", function(event){
-					t.t("rotation" in event);
-					t.t("pageX" in event);
-				});
-				on.emit(div, "touchstart", {changedTouches: [{pageX:100}]});
-			}
-		}
-	]
-);
+dojo.provide("dojo.tests.on");
+
+var on = dojo.require("dojo.on");
+var has = dojo.require("dojo.has");
+var topic = dojo.require("dojo.topic");
+var Evented = dojo.require("dojo.Evented");
+doh.register("tests.on",
+	[
+		function object(t){
+			var order = [];
+			var obj = new dojo.Evented();
+			obj.oncustom = function(event){
+				order.push(event.a);
+				return event.a+1;
+			};
+			var signal = on.pausable(obj, "custom", function(event){
+				order.push(0);
+				return event.a+1;
+			});
+			obj.oncustom({a:0});
+			var signal2 = on(obj, "custom, foo", function(event){
+				order.push(event.a);
+			});
+			on.emit(obj, "custom", {
+				a: 3
+			});
+			signal.pause();
+			var signal3 = on(obj, "custom", function(a){
+				order.push(3);
+			}, true);
+			on.emit(obj, "custom", {
+				a: 3
+			});
+			signal2.remove();
+			signal.resume();
+			on.emit(obj, "custom", {
+				a: 6
+			});
+			signal3.remove();
+			var signal4 = on(obj, "foo, custom", function(a){
+				order.push(4);
+			}, true);
+			signal.remove();
+			on.emit(obj, "custom", {
+				a: 7
+			});
+			t.is(order, [0,0,3,0,3,3,3,3,6,0,3,7,4]);
+		},
+		function once(t){
+			var order = [];
+			var obj = new dojo.Evented();
+			obj.on("custom", function(event){
+				order.push(event.a);
+			});
+			var signal = on.once(obj, "custom", function(event){
+				order.push(1);
+			});
+			obj.emit("custom",{a:0});
+			obj.oncustom({a:2}); // should call original method, but not listener
+			t.is(order, [0,1,2]);
+		},
+		function dom(t){
+			var div = document.body.appendChild(document.createElement("div"));
+			var span = div.appendChild(document.createElement("span"));
+			var order = [];
+			var signal = on(div,"custom", function(event){
+				order.push(event.a);
+				event.addedProp += "ue";
+			});
+			on(span,"custom", function(event){
+				event.addedProp = "val";
+			});
+			on.emit(div, "custom", {
+				target: div,
+				currentTarget:div,
+				relatedTarget: div,
+				a: 0
+			});
+			on.emit(div, "otherevent", {
+				a: 0
+			});
+			t.is(on.emit(span, "custom", {
+				a: 1,
+				bubbles: true,
+				cancelable: true
+			}).addedProp, "value");
+			t.t(on.emit(span, "custom", {
+				a: 1,
+				bubbles: false,
+				cancelable: true
+			}));
+			var signal2 = on.pausable(div,"custom", function(event){
+				order.push(event.a + 1);
+				event.preventDefault();
+			});
+			t.f(on.emit(span, "custom", {
+				a: 2,
+				bubbles: true,
+				cancelable: true
+			}));
+			signal2.pause();
+			t.is(on.emit(span, "custom", {
+				a: 4,
+				bubbles: true,
+				cancelable: true
+			}).type, "custom");
+			signal2.resume();
+			signal.remove();
+			t.f(on.emit(span, "custom", {
+				a: 4,
+				bubbles: true,
+				cancelable: true
+			}));
+			on(span, "custom", function(event){
+				order.push(6);
+				event.stopPropagation();
+			});
+			t.t(on.emit(span, "custom", {
+				a: 1,
+				bubbles: true,
+				cancelable: true
+			}));
+			var button = div.appendChild(document.createElement("button"));
+			// make sure we are propagating natively created events too
+			signal = on(div, "click", function(){
+				order.push(7);
+			});
+			button.click();
+			signal.remove();
+			// test out event delegation
+			if(dojo.query){
+				// if dojo.query is loaded, test event delegation
+				on(div, "button:click", function(){
+					order.push(8);
+				});
+				button.click();
+			}else{//just pass then
+				order.push(8);
+			}
+			t.is(order, [0, 1, 2, 3, 4, 5, 6, 7, 8]);
+		},
+/*
+ This only works if the test page has the focus, so you can enable if you want to test focus functionality and allow the test page to have focus  
+ 		function focus(t){
+			var div = document.body.appendChild(document.createElement("div"));
+			var input = div.appendChild(document.createElement("input"));
+			var order = [];
+			var signal = on(div,"input:focusin", function(event){
+				order.push('in');
+			});
+			var signal = on(div,"input:focusout", function(event){
+				order.push('out');
+			});
+			var otherInput = document.body.appendChild(document.createElement("input"));
+			input.focus();
+			otherInput.focus();
+			d = new doh.Deferred();
+			setTimeout(function(){
+				t.is(['in', 'out'], order);
+				d.callback(true);
+			}, 1);
+			return d;
+		},*/
+		function extensionEvent(t){
+			var div = document.body.appendChild(document.createElement("div"));
+			var span = div.appendChild(document.createElement("span"));
+			span.setAttribute("foo", 2);
+			var order = [];
+			var customEvent = function(target, listener){
+				return on(target, "custom", listener);
+			};
+			var signal = on(div, customEvent, function(event){
+				order.push(event.a);
+			});
+			var signal = on(div, on.selector("span", customEvent), function(event){
+				order.push(+this.getAttribute("foo"));
+			});
+			on.emit(div, "custom", {
+				a: 0
+			});
+			// should trigger selector
+			t.t(on.emit(span, "custom", {
+				a: 1,
+				bubbles: true,
+				cancelable: true
+			}));
+			// shouldn't trigger selector
+			t.t(on.emit(div, "custom", {
+				a: 3,
+				bubbles: true,
+				cancelable: true
+			}));
+			t.is(order, [0, 1, 2, 3]);
+		},
+		function testEvented(t){
+			var MyClass = dojo.declare([Evented],{
+
+			});
+			var order = [];
+			myObject = new MyClass;
+			myObject.on("custom", function(event){
+				order.push(event.a);
+			});
+			myObject.emit("custom", {a:0});
+			t.is(order, [0]);
+		},
+		function pubsub(t){
+			var fooCount = 0;
+			topic.subscribe("/test/foo", function(event, secondArg){
+				t.is("value", event.foo);
+				t.is("second", secondArg);
+				fooCount++;
+			});
+			topic.publish("/test/foo", {foo: "value"}, "second");
+			t.is(1, fooCount);
+		},
+		function touch(t){
+			console.log("has", has);
+			if(has("touch")){
+				var div = document.body.appendChild(document.createElement("div"));
+				on(div, "touchstart", function(event){
+					t.t("rotation" in event);
+					t.t("pageX" in event);
+				});
+				on.emit(div, "touchstart", {changedTouches: [{pageX:100}]});
+			}
+		}
+	]
+);
diff --git a/topic.js b/topic.js
index 96dcc90..b29cfa3 100644
--- a/topic.js
+++ b/topic.js
@@ -1,33 +1,33 @@
-define(["./Evented"], function(Evented){
-	// summary:
-	//		The export of this module is a pubsub hub
-	//		You can also use listen function itself as a pub/sub hub:
-	//		| 	topic.subscribe("some/topic", function(event){
-	//		|	... do something with event
-	//		|	});
-	//		|	topic.publish("some/topic", {name:"some event", ...});
-
-	var hub = new Evented;
-	return {
-		publish: function(topic, event){
-			// summary:
-			//		Publishes a message to a topic on the pub/sub hub. All arguments after
-			// 		the first will be passed to the subscribers, so any number of arguments
-			// 		can be provided (not just event).
-			// topic: String
-			//		The name of the topic to publish to
-			// event: Object
-			//		An event to distribute to the topic listeners
-			return hub.emit.apply(hub, arguments);
-		},
-		subscribe: function(topic, listener){
-			// summary:
-			//		Subcribes to a topic on the pub/sub hub
-			// topic: String
-			//		The topic to subscribe to
-			//	listener: Function
-			//		A function to call when a message is published to the given topic
-			return hub.on.apply(hub, arguments);
-		}
-	}
-});
+define(["./Evented"], function(Evented){
+	// summary:
+	//		The export of this module is a pubsub hub
+	//		You can also use listen function itself as a pub/sub hub:
+	//		| 	topic.subscribe("some/topic", function(event){
+	//		|	... do something with event
+	//		|	});
+	//		|	topic.publish("some/topic", {name:"some event", ...});
+
+	var hub = new Evented;
+	return {
+		publish: function(topic, event){
+			// summary:
+			//		Publishes a message to a topic on the pub/sub hub. All arguments after
+			// 		the first will be passed to the subscribers, so any number of arguments
+			// 		can be provided (not just event).
+			// topic: String
+			//		The name of the topic to publish to
+			// event: Object
+			//		An event to distribute to the topic listeners
+			return hub.emit.apply(hub, arguments);
+		},
+		subscribe: function(topic, listener){
+			// summary:
+			//		Subcribes to a topic on the pub/sub hub
+			// topic: String
+			//		The topic to subscribe to
+			//	listener: Function
+			//		A function to call when a message is published to the given topic
+			return hub.on.apply(hub, arguments);
+		}
+	}
+});

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/dojo.git



More information about the Pkg-javascript-commits mailing list